242 Commits

Author SHA1 Message Date
cg33
e993ba7c05 fix(kimi): conditionally pass --print so newer Kimi Code CLI works (#1456) (#1461)
* fix(kimi): conditionally pass --print so newer Kimi Code CLI works (#1456)

## Problem

`cc-connect` unconditionally passes `--print --output-format stream-json
--prompt …` to the Kimi CLI. The newer Kimi Code CLI removed the
standalone `--print` flag and now exits immediately with

    error: unknown option '--print' (Did you mean --prompt?)

so every Kimi chat is broken for users on the new CLI. Issue #1456.

## Root cause

The two CLIs in the wild have opposing requirements for non-interactive
runs:

| CLI            | --print? | --output-format requires |
|----------------|----------|--------------------------|
| legacy kimi-cli| yes      | --print                  |
| new Kimi Code  | removed  | --prompt                 |

A fixed arg list cannot satisfy both, and `--print` cannot be emulated
the way #1253 emulates `--quiet` — it is the CLI's own non-interactive
mode toggle, not output formatting.

## Fix

Probe `kimi --help` once when the Agent is constructed and cache the
detected flag set. `buildArgs()` (newly extracted from `Send()` so it is
unit-testable) only emits `--print` when the installed binary still
advertises it. Probe failure / timeout falls back to "no --print", which
matches the direction the Kimi CLI is moving and avoids the hard-failure
mode of the current code.

- `agent/kimi/probe.go` — `parseKimiHelpFlags()` pure parser + bounded
  `probeKimiFlags()` (5s timeout, swallows errors).
- `agent/kimi/kimi.go` — Agent caches `kimiFlagSupport`, threads it into
  `newKimiSession`; doc comments updated.
- `agent/kimi/session.go` — `kimiSession.flagSupport` + `buildArgs()`
  helper; conditional `--print`; permission-mode comment updated to
  cover both legacy (`--print` implicit `--yolo`) and modern (`--prompt`
  auto-permission) behaviors.

## Tests

- `TestBuildArgs_NoPrintSupportOmitsPrintFlag` — regression test for
  #1456; fails on pre-fix code, passes on this branch.
- `TestBuildArgs_PrintSupportIncludesPrintFlag` — legacy CLI branch.
- `TestBuildArgs_PlanMode` / `TestBuildArgs_ResumeSession` — sanity
  coverage for other arg paths.
- `TestParseKimiHelpFlags_LegacyAdvertisesPrint` /
  `TestParseKimiHelpFlags_ModernHidesPrint` — parser handles both typer
  box-drawing and standard click `-p, --prompt` layouts.
- `TestParseKimiHelpFlags_IgnoresPositionalAndShortOnly` — robustness.
- `TestProbeKimiFlags_FallbackOnMissingBinary` — probe failure path
  returns zero value (modern-CLI default).

Full suite verified: `go test ./agent/kimi/...` (and `-race`), plus
`go test ./core/ -run TestCUJ`. Pre-existing `agent/acp` integration
test still fails on `origin/main` (requires `cursor agent login`) —
unrelated to this change.

## Non-goals

- Does not touch the cursor agent; Claude Code CLI still supports
  `--print` so cursor's hard-coded flag is fine.
- Does not change `--quiet` handling; PR #1253 owns that fix for #806.
- Does not introduce new config schema.

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

* test(kimi): wrap deferred Close in func to satisfy errcheck

CI lint failed with 3 (and a 4th caught locally) `defer ks.Close()`
sites that ignore the returned error. Wrap in a closure that
explicitly discards the return value so golangci-lint errcheck is
happy and the tests still run.

No functional change.

---------

Co-authored-by: dev-claudecode <dev-claudecode@cc-connect.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-28 21:22:12 +08:00
cg33
303fd46de0 fix(claudecode): chmod 0o644 on per-spawn system-prompt temp file (#1429) (#1433)
writeTempAppendPromptFile (the 1% edge-case path for prompts that have
session-specific platform formatting or user append_system_prompt) used
os.CreateTemp, which leaves the file at mode 0600 owned by the
cc-connect process user (often root under systemd). When the agent
was spawned under a different run_as_user, the target user got EACCES
and the agent exited before reading any prompt.

Fix: f.Chmod(0o644) immediately after write, mirroring the shared
ensureSharedSystemPromptFile path (which already writes 0o644 via
writeFileAtomic). The per-spawn content is a superset of the already
shared base prompt, so 0644 is consistent with the shared file.

The shared-file path (ensureSharedSystemPromptFile, used for the
common 99% case where no platform/user append is set) is already 0644
and untouched here. The daemon-mode path resolution fix from #1419
and the v1.3.4 cmdline 8192 fix from #1376 are independent and not
modified.

Test: TestWriteTempAppendPromptFile_ReadableByOtherUser asserts the
on-disk mode is 0o644 (the run_as_user contract) and that an
O_RDONLY open succeeds — same access path the spawned agent uses
for --append-system-prompt-file.

Co-authored-by: dev-claudecode <dev-claudecode@cc-connect.local>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-28 20:34: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
coolrockin
a5d441e98e fix(claudecode): emit EventToolResult so tool output reaches progress card (#1407)
* fix(claudecode): emit EventToolResult so tool output reaches progress card

## 背景

cc-connect 的飞书卡片(以及其他平台的 progress card)渲染工具结果
依赖 engine 收到 EventToolResult 事件。engine.go:4745 的 case
EventToolResult 会调用 formatProgressToolResult / cp.AppendEvent
把工具输出渲染到卡片。

## 问题

agent/claudecode/session.go 的 handleUser 函数处理 stream-json
里的 tool_result content block 时,原本只做了一件事:

  if isError { slog.Debug("claudeSession: tool error", ...) }

也就是 **error 情况只记日志,正常情况完全静默丢弃**,始终没有
emit EventToolResult 事件给 engine。

对照 agent/codex/session.go:522 case "command_execution":codex
agent 在工具完成时正确构造了 EventToolResult 事件并发送到
cs.events channel,engine 收到后才能渲染工具结果卡片。

## 用户感知的现象

- claude-multi 飞书群里调工具后,**只看到最终文字回复,看不到
  工具调用面板和工具结果**
- codex-multi 飞书群里调工具后,能看到完整的 "工具调用 + 工具结果"
  卡片渲染
- 两个 project 的 cc-connect 配置完全一致,差异只在 agent type

之前误以为是 stream preview / 飞书 universal card payload
(ErrCode 200800) 等问题,实际那些是次要现象 —— 真正的根因是
claudecode agent 根本没把工具结果事件转发给 engine。

## 方案

最小化修复:在 if contentType == "tool_result" 分支里,无论
isError 与否都构造 EventToolResult 事件 emit 出去。

实现细节:
- content 字段兼容两种格式:string 直接用;array of {type:"text",
  text:"..."} 拼接所有 text 块(Anthropic SDK 两种格式都可能出现)
- 工具名留空:Anthropic 的 tool_result block 只带 tool_use_id 不
  带工具名,反查 id→name 映射需要额外缓存且容易出错。视觉上工具
  调用面板和结果面板按顺序排列,用户能自行配对,因此留空可接受
  (飞书 buildToolDisplay 对空名 fallback 显示为 "Tool")
- exit code: isError → 1, 否则 0;success: !isError
- 复用包内已有的 truncateStr 截断到 500 字符(与 codex agent 一致)

## 影响范围

- 只改 agent/claudecode/session.go 一处(handleUser 函数)
- 不影响 codex / gemini / opencode 等其他 agent
- 不影响 engine 及下游渲染逻辑(只是补上之前缺失的事件源)

* test(claudecode): regression test for EventToolResult emit
2026-06-23 07:22:13 +08:00
Han
355793eaee refactor(agent): centralize cmd/env option parsing into core with unified cmd field (#1297)
* refactor: centralize cmd/env option parsing into core

- Add core.ParseCmdOpts() to unify cmd/cli_path/command option
  parsing across all agents, with deprecation warnings for old keys
- Add core.ParseConfigEnv() to parse [projects.agent.options.env]
  from config into []string KEY=VALUE format
- Rename cliBin/command struct fields to cmd consistently
- Add cliExtraArgs support so cmd="binary arg1 arg2" works
- Add configEnv field for static env that persists across SetSessionEnv
- Fix env merge order: configEnv < providerEnv < sessionEnv (was
  inconsistent in copilot and opencode agents)
- Update all tests for renamed fields

* fix(claudecode): add backward compat for deprecated cli_args_flag

Users with cli_args_flag in their config.toml will see a deprecation
warning directing them to the new cmd_args_flag key.

* docs(config): update config examples to use cmd instead of deprecated keys

- config.example.toml: cli_path → cmd, command(S) → S(6 occurrences)
- claudecode/claudecode.go: comment cli_path → cmd
- copilot/copilot_test.go: comment cliBin/cli_path → cmd

* test(core): add direct unit tests for ParseCmdOpts and ParseConfigEnv

Address review feedback on PR #1297 (P2). The two helper functions in
core/cmdopts.go are depended on by 13 agent packages; previously their
behavior was only covered indirectly via agent-level New() tests. This
commit adds direct unit tests covering:

- ParseCmdOpts: four-tier priority (cmd / cli_path / command / default),
  empty/whitespace boundaries, tokenization of extra args, no-warning
  for canonical cmd field, and capture of deprecation warnings.
- ParseConfigEnv: nil / missing key, map[string]string, map[string]any
  (TOML parser output), non-string value filtering, unsupported types,
  and input non-mutation.

Also adds structured slog attrs (deprecated_key, new_key) to all three
deprecation warnings (cli_path, command, cli_args_flag) so that future
log aggregation can scan deprecated-key usage without code changes
(review feedback P3).

Ref: PR #1297 review.

* fix(codex): use local cmd var (not stale cliBin name) in struct init

Post-rebase fixup: the struct field was renamed cliBin -> cmd in
PR #1297, and the local variable returned by core.ParseCmdOpts is
also named cmd. The rebased struct initializer still referenced
the old name 'cliBin', which no longer exists in scope. Assign
the local cmd variable to the cmd struct field.
2026-06-23 07:05:16 +08:00
Han
8e3203a7b7 feat(codex): prefer Codex model_catalog_json as highest-priority model source (#1074)
- Add readCodexModelCatalog() that reads $CODEX_HOME/config.toml,
  resolves model_catalog_json path (expand ~, relative to CODEX_HOME),
  and parses the JSON as the primary model list
- Extract shared parseCodexModelsJSON() to deduplicate JSON parsing
  logic between readCodexCachedModels and readCodexModelCatalog
- Refactor readCodexCachedModels() to reuse resolveCodexHome(nil)
- Update AvailableModels() priority:
  1. model_catalog_json (new, highest)
  2. provider config
  3. GET /v1/models API
  4. models_cache.json
  5. hardcoded fallback
- Add tests: TestAvailableModels_UsesModelCatalog, TestReadCodexModelCatalog_NoConfigFile
2026-06-23 06:58:40 +08:00
SXongin
2d4a0bbfe3 fix(acp): add AgentSessionCanceller interface for graceful /stop (#1275)
When /stop is issued against an ACP session, the engine was killing the
entire subprocess via Process.Kill(), destroying the session. For ACP
agents like OpenCode, the subprocess is a long-lived server that should
survive /stop — only the current turn should be cancelled.

This change introduces a clean, opt-in mechanism:

1. Adds AgentSessionCanceller interface in core/interfaces.go with a
   single CancelTurn() method. Sessions that implement it signal that
   /stop should cancel only the current turn, not kill the process.

2. Adds transport.sendNotification() in agent/acp/rpc.go for sending
   JSON-RPC 2.0 notifications (no response expected).

3. Implements CancelTurn() on acpSession: sends an ACP session/cancel
   notification to abort the current LLM request while keeping the
   process alive for the next user message.

4. Modifies stopInteractiveSessionWithOptions in the engine: when the
   agent session implements AgentSessionCanceller, calls CancelTurn()
   instead of markStopped + delete + close. Sets eventsNeedResync=true
   so stale events from the cancelled turn are drained before the next
   turn starts.

The engine falls back to the existing Close() path if CancelTurn()
returns an error, ensuring backward compatibility.

Co-authored-by: SXongin <sxongin@users.noreply.github.com>
2026-06-21 08:32:10 +08:00
Haiyi
c1466312e5 feat(codex): support custom system_prompt / append_system_prompt config (#1345)
* feat(codex): support custom system_prompt / append_system_prompt config

Codex has no native system-prompt CLI flag, so these project options are
synthesized into a preamble and prepended to the first message of each new
session. Resumed sessions are not re-injected (preambleSent is preset for
resume IDs). Covers both the exec and app_server backends.

Adds config.example.toml documentation for the two new options.

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

* test(codex): check cs.Close return value to satisfy errcheck

CI lints new lines with golangci-lint --new-from-rev; the freshly added
TestSend_PrependsProjectPromptOnFreshSession used an unchecked defer
cs.Close(). Wrap it in a deferred closure that explicitly ignores the
error, matching the errcheck-clean pattern.

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

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 12:15:19 +08:00
cg33
cf2d4f1b81 fix(claudecode): use --append-system-prompt-file to fix Windows cmdline limit (#1376) (#1378)
cc-connect's built-in AgentSystemPrompt is ~9KB, which on its own
exceeds Windows cmd.exe's 8192-byte command-line limit when claude
is spawned with --append-system-prompt <inline content>. The
claude.exe child immediately fails with GBK stderr "命令行太长。"
(command line too long) before any user message reaches the agent.
On v1.3.3 this breaks every Feishu / IM message on Windows hosts.

Pass the merged prompt through Claude Code CLI's
--append-system-prompt-file <path> flag instead of the inline form.
Only the short file path travels on the command line, so the cap is
no longer a function of prompt size.

Common case (99% of users — no platform formatting hints, no
user-configured append_system_prompt):

  * On agent construction, write the full AgentSystemPrompt() once to
    <data_dir>/agent-prompts/cc-connect-system.md (default
    ~/.cc-connect/agent-prompts/cc-connect-system.md). claude reads
    this file at every spawn; cc-connect never rewrites it unless the
    cc-connect version actually changes the prompt content.
  * Every spawn reuses the same file, so there is no per-spawn write
    and no concurrency race (claude is a strict reader).

Edge case (Slack / Weixin / MAX with FormattingInstructions, or
project-level append_system_prompt):

  * Write a per-spawn temp file under <data_dir>/agent-prompts/
    holding the merged content, passed via the same flag.
  * Cleaned up on session Close to avoid leaking files.

Notes for reviewers:

  * claude CLI refuses --append-system-prompt and
    --append-system-prompt-file together
    ("Cannot use both ... Please use only one"), so the merged content
    must travel as a single file.
  * Only the claudecode agent runtime is affected. Other agents
    (codex/opencode/qoder/cursor/gemini/kimi) inject AgentSystemPrompt
    via memory files (CLAUDE.md/AGENTS.md/...), which already have no
    cmdline cap.
  * core/interfaces.go (AgentSystemPrompt content) is unchanged from
    v1.3.3; the full prompt is preserved so agent behaviour does not
    regress.

Tests:

  * TestEnsureSharedSystemPromptFile_WritesOnceAndReuses — verifies the
    shared file is written once and skipped on identical content.
  * TestEnsureSharedSystemPromptFile_RewritesOnContentChange — verifies
    cc-connect upgrades refresh the shared file.
  * TestEnsureSharedSystemPromptFile_EmptyDirUsesTempDir — verifies the
    fallback when ccDataDir is unset.
  * TestWriteTempAppendPromptFile_UniquePerCall — verifies concurrent
    edge-case spawns get unique paths.
  * Existing claudecode + core suites all pass (one pre-existing flake
    in TestCUJ_H2_TwoPlatformsConcurrentNoBleed is unrelated to this
    change and still passes when run in isolation).

E2E (Windows, MiniMax-M3 backend, Feishu platform):

  * Before fix: every Feishu message produces no reply; claude.exe
    fails with "命令行太长。" on stderr.
  * After fix: "你好" → MiniMax intro reply; "3 分钟后帮我看看
    ipconfig" → timer correctly created in data/timers/jobs.json;
    "每天早上 6 点提醒我吃药" → cron correctly created in
    data/crons/jobs.json. Agent uses /timer and /cron commands as
    instructed by the prompt.

Fixes #1376.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 16:21:26 +08:00
Byctor
2548b66c46 feat: add plugin_dir option to load Claude Code plugins via --plugin-dir (#1325)
Adds `plugin_dir` support to `agent.options` in config.toml so that
cc-connect can pass `--plugin-dir` flags to Claude Code when spawning
sessions, enabling installed plugins (like superpowers, last30days) to
be loaded in IM-bridged sessions.

Supports both single string and array:
  plugin_dir = "/path/to/plugins/cache/xyz"       # single
  plugin_dir = ["/path/a", "/path/b"]             # multiple

The option propagates to multi-workspace agents via
WorkspaceAgentOptions().

Closes #1324
2026-06-16 10:02:37 +08:00
Baocang Nie
58c7e27cc3 fix(runas): run agent in its workspace under run_as_user (#1315)
sudo -i simulates a login and runs the command from the target user's HOME,
silently overriding cmd.Dir. Under run_as_user the agent therefore ignored its
(multi-workspace) working directory and started in HOME, so it couldn't see the
bound workspace or its CLAUDE.md.

Re-establish the intended cwd inside the spawn: when SpawnOptions.WorkDir is set,
BuildSpawnCommand wraps the command to 'cd "$CC_RUNAS_CHDIR" && exec "$@"'.
The path travels via the preserved env var (not argv) so non-ASCII/space paths
survive sudo's command re-quoting.

Fixes #1312
2026-06-16 10:01:32 +08:00
cg33
23ebad3b02 fix(claudecode): keep turn running on mid-turn compaction event (fixes #481) (#1272)
* fix(claudecode): keep turn running on mid-turn compaction event (fixes #481)

Claude Code's stream-json protocol emits a `type:"result"` event with
`subtype:"compact"` (newer CLI) or `subtype:"compaction"` (older
CLI) when it performs automatic context compaction mid-turn. The
existing handleResult treated every result event as turn completion
(Done=true), so the engine's processInteractiveEvents loop would
return early and drop any subsequent tool calls and assistant
messages for the same turn.

Recognize the compaction subtypes and emit EventResult with
Done=false so the event loop keeps reading from the CLI process. Add
a default case to the readLoop event switch that logs unrecognized
event types at debug level (with the full payload) so future new
event shapes are diagnosable from the log stream.

Rebuild of #483. The original PR also referenced adding diagnostic
logging for unknown event types; that change is included as the new
default case.

- Add isCompactionResult / resultSubtype helpers in session.go.
- Set Done=!isCompaction in handleResult's emitted EventResult.
- Add default case to readLoop's event switch with slog.Debug.
- Add TestHandleResultCompactionSubtypeIsNotTerminal and
  TestIsCompactionResult regression tests; tighten existing
  TestHandleResultParsesUsage with a Done=true assertion.

* fix(core): gate EventResult case body on event.Done (fixes #481)

The previous PR #1272 fix changed the agent-side handleResult to set
Done=!isCompaction, but processInteractiveEvents in core/engine.go never
read event.Done — every EventResult unconditionally ran
cp.Finalize(Completed), AddHistory, noteUserTurnCompleted, and a final
return. So a mid-turn compaction result still caused the engine loop to
exit early, dropping subsequent tool calls and assistant messages.

Gate the entire EventResult case body on event.Done: when an agent
emits a non-terminal result (Done=false) — e.g. mid-turn auto-compact —
slog.Debug it and continue the outer loop to read the next event. All
existing turn-completion side effects and the trailing return only run
when Done=true. The agent-side Done=!isCompaction logic from #1272 is
now effective end-to-end.

Test:
- New TestProcessInteractiveEvents_NonTerminalResultContinuesTurn
  pins issue #481: emits EventResult{Done:false} → EventText →
  EventResult{Done:true} and asserts noteUserTurnCompleted runs exactly
  once (on the terminal result) and the final reply reaches the
  platform. Verified manually that without the engine fix the test
  fails because the compaction event produces an empty '(empty
  response)' message and the loop returns before the final result.
- Existing tests in core/engine_test.go (line 12741, 13026) and
  core/relay_test.go (line 102, 184, 223, 284) that previously sent
  EventResult without setting Done now set Done:true — they were
  relying on the implicit-on EventResult semantics that this change
  inverts.

Verified:
- go test -count=1 -tags no_web -short ./core/...    ok 42s
- go test -count=1 -tags no_web ./agent/claudecode/...  ok
- golangci-lint run --new-from-rev origin/main ./core/...   0 issues

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-16 09:57:21 +08:00
Yu Zhang
2a52fe3c9d fix(qoder): emit streaming text without dropping final result (#1290)
* fix(qoder): emit streaming text without dropping final result

* fix(qoder): bound streaming text dedup cache
2026-06-15 15:21:01 +08:00
cg33
5d1ee3a60c test(agent): add provider-resume regression tests for codex/opencode/kimi (#1366)
Extends PR #1356 coverage: each runtime now has unit tests proving that
SetActiveProvider correctly restores providerEnv and model after a
simulated cc-connect process restart (activeIdx = -1 → SetActiveProvider
called by engine's restoreActiveProviderFromSession).

Tests added:
- TestCodex_SessionResume_PreservesActiveProvider
- TestCodex_SessionResume_ModelFollowsProvider
- TestOpencode_SessionResume_PreservesActiveProvider
- TestOpencode_SessionResume_ModelFollowsProvider
- TestKimi_SessionResume_PreservesActiveProvider
- TestKimi_SessionResume_ModelFollowsProvider

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 14:43:10 +08:00
cg33
139bf9fad5 fix(codex): use -c sandbox_mode override on exec resume (#1360)
`codex exec resume` does NOT accept the `--sandbox <mode>` flag (only
`codex exec` does). Both subcommands accept `-c key=value` config
overrides though, so on resume we now express sandbox via
`-c sandbox_mode="..."` instead of `--sandbox <mode>`.

Without this fix, every codex `exec` backend resume (cc-connect process
restart, idle-reset, etc.) failed with:

  error: unexpected argument '--sandbox' found

silently destroying the user's session on each restart. This regression
was introduced by PR #1351 when the sandbox+approval flags were
generalized across exec/resume paths.

Found while QA'ing the beta release of cc-connect; see release-gate
notes:

- agents/qa-cursor/release-gate/CODEX-PERMISSION-MATRIX.md (case
  CODEX-RESUME-01 + "Known bug 1")
- agents/qa-cursor/release-gate/notes/2026-06-15-beta5-followup-test-plan.md

Tests:

- New: TestBuildExecArgs_ResumeUsesSandboxModeConfigOverride asserts
  that for every mode in {suggest, auto-edit, full-auto, yolo}:
  * the resume invocation never contains a bare `--sandbox` flag
  * sandbox is correctly expressed via `-c sandbox_mode="..."`
    (or `--dangerously-bypass-approvals-and-sandbox` for yolo)
  * approval_policy="never" is still enforced (exec backend has no IPC)
- Existing: TestBuildExecArgs_ModeMapping unchanged (covers first-turn
  `codex exec` path which still uses `--sandbox <mode>`).

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 10:02:21 +08:00
cg33
179e603116 fix(codex): align suggest mode with description; replace deprecated --full-auto (#1351)
Fixes two long-standing inconsistencies on the codex exec backend:

1. `suggest` mode hung silently. Documentation said "ask permission for every
   tool call" but `codex exec` has no approval IPC, so any approval prompt
   blocks waiting for a TTY response that never arrives. Now `suggest` runs
   under read-only sandbox with approval_policy=never — matching what users
   actually need on the exec backend, and matching how lark-coding-agent-bridge
   solves the same problem.

2. `--full-auto` was removed in codex-cli 0.137. Replaced with the canonical
   `--sandbox <mode>` plus `-c approval_policy="never"`. Behavior unchanged.

Mode → flags after this change (exec backend):
  - suggest:   --sandbox read-only       + approval_policy=never
  - auto-edit: --sandbox workspace-write + approval_policy=never (alias)
  - full-auto: --sandbox workspace-write + approval_policy=never
  - yolo:      --dangerously-bypass-approvals-and-sandbox

Documentation updates clarify that real interactive approvals require the
app_server backend (which already implements execCommandApproval /
applyPatchApproval / permissionsApproval / requestUserInput).

No breaking change: mode keys unchanged, existing user configs run with the
same effective sandbox tier. The `suggest` mode goes from "hangs" to
"completes safely under read-only sandbox" — strictly a bug fix.

Adds TestBuildExecArgs_ModeMapping covering all four modes and asserting
--full-auto is no longer emitted.

Refs t-20260614-st7ft2

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 08:32:39 +08:00
cg33
9328cb7d54 fix(claudecode): preserve active provider across session resume (#1356)
Previously a `/provider switch` was held only in the agent's in-memory
`activeIdx`. The user's first message after the switch ran on the
correct provider, and `agent_session_id` was persisted to disk; but
when cc-connect restarted (or any other path that recreated the
*Agent), the in-memory active provider reset to default while the
saved agent_session_id kept the conversation going. The next user
message resumed the saved CLI session under the *default* provider's
base_url and API key, with the model name the agent still "remembered"
from the previous turn — producing 100% reproducible

  "There's an issue with the selected model (X). It may not exist..."

errors against the wrong endpoint.

This change persists the user's provider choice on the Session itself
(new `Session.ActiveProvider` field, `json:"active_provider"`) so it
survives a process restart, and re-binds the agent before each resume:

* `Session` gains `ActiveProvider` plus `Get/SetActiveProvider` helpers.
* `switchProvider` writes the choice to the session and saves.
* `/provider clear` wipes the persisted choice.
* `getOrCreateInteractiveStateWith` calls a new
  `restoreActiveProviderFromSession` helper before `agent.StartSession`
  so the resumed CLI is spawned with the right provider env.

The restore helper is a no-op when the agent already has the right
provider active (steady-state in-process path), when the agent does
not implement ProviderSwitcher, or when the recorded provider name is
no longer registered (gracefully logs a warning instead of clobbering
the default).

Tests:
- core: TestSwitchProvider_PersistsToSession,
        TestProviderClear_ClearsSessionActiveProvider,
        TestRestoreActiveProviderFromSession_AllPaths (5 sub-tests
        covering every branch of the helper).
- claudecode: TestClaudecode_SessionResume_PreservesActiveProvider —
        end-to-end providerEnv check that the simulated post-restart
        re-bind produces ANTHROPIC_BASE_URL/ANTHROPIC_MODEL identical
        to the pre-restart state.

Refs internal task t-20260614-qp7xnl. Same family as #1348 (resume
loses session state); a follow-up should audit codex / opencode /
kimi for the analogous gap.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 08:32:25 +08:00
Han
527220d924 feat(claudecode): respect Claude Code PermissionRequest hooks (#850)
* feat(claudecode): respect Claude Code PermissionRequest hooks

When cc-connect bridges Claude Code via --permission-prompt-tool stdio,
Claude Code's PermissionRequest hooks are executed but their results
are ignored — the control_request is sent on stdout regardless.

This fix adds a hook runner in the claudecode agent that independently
reads and executes the user's PermissionRequest hooks from
~/.claude/settings.json before forwarding permission requests to the
messaging platform. If a hook returns "allow" or "deny", the decision
is respected directly. If the hook returns "ask" or no hook matches,
the existing behavior (forward to platform) is preserved.

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

* feat(claudecode): add CC_CONNECT_PERMISSION_HOOK_SKIP env var

When cc-connect spawns Claude Code, inject
CC_CONNECT_PERMISSION_HOOK_SKIP=1 into the subprocess environment.
PermissionRequest hooks can check this to skip expensive work (e.g.
LLM calls) on the Claude Code side, since the hook result is ignored
anyway when --permission-prompt-tool stdio is active.

cc-connect's own hook runner explicitly strips this env var so the
hook does real work only once — when cc-connect calls it directly.

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

* fix(claudecode): improve cc_hooks protocol compat and test coverage

- Add hook_event_name field to hook stdin for Claude Code protocol compat
- Change hook timeout from 10s to 60s to match Claude Code's own timeout
- Log non-ENOENT errors when loading settings files for debuggability
- Return original data on unclosed block comments in stripJSONC
- Add tests for multi-entry fallthrough, settings merging, deny message
  field, CC_CONNECT_PERMISSION_HOOK_SKIP env stripping, timeout, and
  unclosed block comments

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

* docs: add Claude Code PermissionRequest hooks section to usage guide

Explain that cc-connect re-runs hooks independently (hooks execute twice
per request) and document the CC_CONNECT_PERMISSION_HOOK_SKIP env var
for LLM-based hooks to avoid double token cost.

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

* refactor(claudecode): load hook settings once per session instead of caching

Replace 30s TTL cache with sync.Once — settings are read on first
tryHook call and reused for the session lifetime. Avoids repeated
JSON parsing on every permission request.

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

* refactor(claudecode): introduce hookContext for richer hook stdin payload

Bundle hook parameters into a hookContext struct and add fields that
match Claude Code's PermissionRequest hook input spec: permission_mode,
transcript_path, permission_suggestions, agent_id, agent_type. Optional
fields are omitted from stdin JSON when empty.

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

* fix: lint - errcheck WriteFile/MkdirAll, staticcheck QF1003 switch

* fix: all remaining errcheck WriteFile/MkdirAll in cc_hooks_test.go

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 23:27:46 +08:00
soonwang
f918aaf9da feat(claudecode): support custom append_system_prompt config (#1175)
Add an `append_system_prompt` option for the Claude Code agent so users
can inject extra system-prompt text while keeping Claude's default system
prompt — unlike `system_prompt`, which replaces it entirely.

Claude CLI's --append-system-prompt only honors its last occurrence (a
second flag overwrites the first), so the cc-connect functionality prompt,
platform formatting hints, and the user's custom text are concatenated
into a single flag value via the new buildAppendSystemPrompt helper.

Co-authored-by: wangsong.ws <wangsong.ws@bytedance.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 23:27:03 +08:00
Han
8eab274958 feat(pi): add ContextUsageReporter for reply footer token stats (#1235)
* feat(pi): add ContextUsageReporter for reply footer token stats

Parse ~/.pi/agent/models.json at session start for per-model context
window data. Handle pi's agent_end event to extract assistant message
usage (input, output, cacheRead, cacheWrite) and populate ContextUsage,
enabling the engine's buildClaudeStatusLineFooter to render the CCD-style
token-usage footer for pi agent replies.

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

* fix(pi): address PR #1235 review — log levels, UsedTokens semantics, tests

- Log file-not-found for models.json at Info level (not Warn)
- Fix UsedTokens = input + cacheWrite + cacheRead (was incorrectly
  including output); TotalTokens = UsedTokens + output. Mirrors
  claudecode's per-sub-call pattern.
- Add comments for unpopulated BaselineTokens/ReasoningOutputTokens
  and session-lifetime modelsCW caching
- Add 11 unit tests covering loadModelsContextWindows, handleAgentEnd,
  GetContextUsage edge cases (nil, empty, fallback, copy semantics)

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

* fix(pi): silence errcheck lint in new tests

Add _ = prefix to os.Setenv/os.Unsetenv in Cleanup closures,
and check os.WriteFile errors to satisfy errcheck linter.

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

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 23:21:30 +08:00
Ref/西顾
8dcadfad8e fix(cursor): discover CLI chat storage and show readable session titles (#1232)
Cursor Agent CLI does not always write sessions to ~/.cursor/chats.
When XDG_CONFIG_HOME is set (common on macOS dev setups), chats live
under $XDG_CONFIG_HOME/Cursor/chats instead, so /list returned empty
even though sessions existed on disk.

Most CLI sessions also keep the default name "New Agent" and wrap the
real user prompt in <user_query> tags. The old summary extractor skipped
any content starting with "<", so Feishu /list fell back to opaque
session IDs.

Scan all known CLI storage roots and derive titles from <user_query>
content so /list and /switch are usable from messaging platforms.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-09 23:18:35 +08:00
cg33
30c7605f95 fix(engine): validate session ID belongs to project before resume (#599) (#1276)
When multiple cc-connect projects share a host, a stored AgentSessionID
can point at a session file that lives in a DIFFERENT project's
~/.claude/projects/<key>/ directory. Resuming it would silently load
the wrong project's conversation history into the current project.

Adds an opt-in SessionIDValidator interface (default-agent helper
included) so the engine asks the agent whether a stored ID is valid
BEFORE calling StartSession. If the agent reports the ID does not
belong to this project, the engine clears the stored ID and starts
fresh — preventing the cross-project context leak.

The ClaudeCode agent implements ValidateSessionID by checking for a
<sessionID>.jsonl file under the per-project directory derived from
the agent's workDir.

Fresh implementation supersedes the stale #604 branch (which mixed
#599 validation with the already-merged #603 duplicate-session prune
CLI). No prune-CLI changes are included here.

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-09 23:14:35 +08:00
cg33
a82b01aa27 fix(opencode): eliminate TempDir cleanup race in TestAvailableModels under -cover (#1118) (#1254)
Root cause: AvailableModels() with a warm persistent cache calls
startPersistentModelRefresh(), which spawns a background goroutine that
writes the refreshed model list into the test's TempDir.  When the test
function returns, t.TempDir() runs RemoveAll before that goroutine
finishes its last write — manifesting as:

  TempDir RemoveAll cleanup: unlinkat /tmp/.../001: directory not empty

The race window is too small to hit reliably without -cover; coverage
instrumentation slows the goroutine enough to make it reproducible.

Fix (two-part):
1. Add refreshWg sync.WaitGroup to Agent and track every background
   refresh goroutine with Add(1)/Done() in startPersistentModelRefresh.
   This is a pure bookkeeping addition with zero production behaviour
   change.
2. In TestAvailableModels_PrefersPersistentCacheOverDiscoveredModels,
   register t.Cleanup(func() { a.refreshWg.Wait() }) immediately after
   creating the agent (before AvailableModels is called). Cleanup
   functions run LIFO: our Wait fires before t.TempDir's RemoveAll,
   guaranteeing the goroutine has finished writing before the directory
   is cleaned up.

Verified: go test -count=1 -cover ./agent/opencode/... run 10 times
consecutively — 10/10 PASS, 0 failures.

Co-authored-by: root <root@UYQQVGRAEKQKNQP>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-07 21:18:36 +08:00
cg33
f4d36dbbdf fix(opencode): surface tool rejection error as text to prevent empty response (#178) (#1247)
When opencode rejects a tool call in default mode (e.g. bash permission
denied), it emits a tool_use event with status="error" then exits without
generating any follow-up text. This caused the engine to fall through to
the "(空响应)" / "(empty response)" placeholder since textParts was empty.

Fix: when handleToolUse receives status="error" with a non-empty error
message, emit an EventText containing the rejection reason. This ensures
textParts is populated and the user sees why the command was blocked (e.g.
"The user rejected permission to use this specific tool call.") rather
than a silent empty response.

Three scenarios handled:
- Permission denied (default mode): error text surfaced ✓
- Tool completed successfully: no change ✓
- Error with no message: no spurious empty EventText ✓

To avoid permission rejections entirely, set mode="yolo" in config or
configure opencode's permission settings to allow the required tools.

Fixes #178

Co-authored-by: root <root@UYQQVGRAEKQKNQP>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-07 21:18:25 +08:00
cg33
faeef53cd9 fix: address P1/P2 issues from post-merge QA review (#1246)
## P1 fixes

- core/engine_test: fix stubCompactProgressPlatform.BuildRichCard signature
  The last parameter was still `elapsed time.Duration` (old interface) after
  #1204 changed RichCardSupporter to `statusFooter string`. The mismatch
  caused the stub to silently NOT satisfy the interface at runtime, so all
  tests using it were bypassing the rich-card path entirely.

- platform/slack: warn when session_scope=thread without window_per_session
  Thread-scoped sessions require per-session isolation at the agent level.
  When using tmux, window_per_session=true must also be set or concurrent
  threads will share a single pane and their output will interleave.

## P2 fixes

- core/relay: warn on unknown visibility mode instead of silent fallback
  normalizeRelayVisibility previously fell back to "full" silently for
  unrecognised values. Now logs a structured Warn with valid options listed.

- platform/feishu: map common video formats to FileTypeMp4 (Media message)
  CLI accepted .webm/.mov/.avi/.mkv as video, but detectFeishuFileType only
  recognised .mp4, sending others as generic file downloads. Expanded the
  detection to cover all common video MIME types and extensions so they
  render as native Feishu video player bubbles. Playback compatibility
  (e.g. webm/mkv) depends on the Feishu client platform.

- agent/{claudecode,qoder}: surface root bypass-downgrade warning to IM user
  When running as root, bypassPermissions (Claude) and yolo (Qoder) modes
  are silently downgraded. Users were confused why the agent kept asking for
  permissions. Added StartupWarner interface (core/interfaces.go) so the
  engine can emit a one-time IM notification after session start.

Co-authored-by: root <root@UYQQVGRAEKQKNQP>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-07 21:14:30 +08:00
cg33
f1a1fae5e0 fix(cursor): implement interaction_query permission flow for default mode (#785) (#1252)
Root cause: in --print mode, Cursor Agent sends interaction_query/request on
stdout and waits for a JSON response on its stdin before executing or rejecting
a tool (WebFetch, Bash, etc.). cc-connect had no stdin pipe connected, so
Cursor received EOF and auto-rejected every tool call silently.

Changes in agent/cursor/session.go:
- Add stdin io.WriteCloser field (protected by stdinMu) to cursorSession.
- Send() creates a StdinPipe() and stores it; readLoop closes it on exit.
- handleInteractionQuery() now:
  - auto-approves when skipApproval=true (Cursor marks as safe)
  - emits EventPermissionRequest (default mode) so the engine can ask the user
  - auto-denies for plan/ask modes (read-only, no tool execution expected)
  - auto-denies unknown query types to unblock Cursor
- writeInteractionResponse() marshals the correct Cursor response JSON
  ("approved"/{} or "rejected"/{reason}) and writes it to stdin.
- RespondPermission() is now a real implementation that looks up the pending
  interaction query and delegates to writeInteractionResponse().

New tests in agent/cursor/permission_test.go cover:
- EventPermissionRequest emitted for webFetchRequestQuery (default mode)
- EventPermissionRequest emitted for shellRequestQuery (Windows bug scenario)
- skipApproval=true → auto-approve, no EventPermissionRequest
- plan/ask modes → auto-deny, no EventPermissionRequest
- RespondPermission approve → correct JSON on stdin
- RespondPermission deny → correct JSON with reason on stdin
- RespondPermission with no pending → no-op (no panic)
- response JSON format for all four query×outcome combinations

Co-authored-by: root <root@UYQQVGRAEKQKNQP>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-07 21:13:43 +08:00
cg33
3087e8563f fix(acp): improve vendor compatibility for session/update parsing (#434)
Add support for alternative JSON formats in ACP session/update messages
to handle different vendor implementations (OpenClaw, OpenCode, etc.).

Changes:
- Add debug logging to capture raw session/update JSON for troubleshooting
- Support multiple text field formats in mapAgentMessageChunk:
  - Standard ACP: content.text with type field
  - Alternative: content.text without type
  - Alternative: top-level text field
  - Alternative: content as string
- Enhance fallback text extraction for unknown sessionUpdate types
- Add tests for all alternative formats

Fixes #432

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-07 14:53:47 +08:00
Shawn
330e3c25db fix(cursor): discover skills under native .cursor/skills layout (#885)
Cursor agent's SkillDirs() only returned .claude/skills paths, so skills
placed under .cursor/skills/<name>/SKILL.md (Cursor's documented layout)
were silently invisible to /skills until users renamed the directory.

Add .cursor/skills (project work dir + user home) ahead of the existing
.claude/skills entries so the cursor-native location is searched first
while keeping backward compatibility with setups that already rely on
.claude/skills.

Fixes #786
2026-06-07 09:25:06 +08:00
Kagura
7c097e6239 fix(claudecode): encode dot and @ in project key to match Claude Code behavior (#1055)
Claude Code replaces '.' and '@' with '-' when deriving project directory
names (e.g., '/home/user/.nvm/.../@anthropic-ai/...' becomes
'-home-user--nvm-...-anthropic-ai-...'). The existing encodeClaudeProjectKey
function only replaced '/', ':', '_', ' ', '~', and non-ASCII characters,
causing findProjectDir to fail when work directories contain dots (hidden
dirs, version numbers) or @ (scoped npm packages).

This made /list always return empty for affected paths because the generated
key didn't match Claude Code's on-disk project directory name.

Closes #1046
2026-06-07 09:24:15 +08:00
Kagura
cf2d258557 fix(agent): skip bypass-permissions flags when running as root (#1056)
Claude Code and Qoder reject permission-bypass flags when the
process runs as root (EUID 0). This causes the agent to crash
with exit status 1, and the nil agentSession triggers a panic in
the engine's interactive message handler.

For Claude Code: downgrade bypassPermissions mode to auto (which
auto-approves permissions internally in cc-connect, avoiding the
CLI flag entirely).

For Qoder: skip --dangerously-skip-permissions under root.

Both log a warning so the user knows why YOLO mode is degraded.

Closes #1054
2026-06-07 09:23:49 +08:00
Claude
f86c26634b fix(opencode): pass --agent flag when agent config option is set (#1210)
Adds optional 'agent' config option under [projects.agent.options] for
opencode. When set, the value is passed as --agent to every 'opencode run'
invocation, enabling plugin-defined agents (e.g. oh-my-openagent's
'Sisyphus - Ultraworker') to work correctly without falling back to the
default agent.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 10:17:34 +08:00
Claude
410d46e5bf feat(feishu): refresh rich card rendering and panel handling (#1204)
Squash merge of PR #1204 (rebased onto main, minor conflicts resolved).
Adds structured per-turn reply footer, cardkit-v1 streaming, status footer
interface, claude context usage tracking, and rich card body improvements.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 10:05:17 +08:00
Claude
1fdb01088f feat(codex): support request_user_input app-server events (#1200)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 09:56:24 +08:00
masakasu
f70d494fe9 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>
2026-06-04 09:49:37 +08:00
Han
fa25d739d9 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
2026-06-04 09:48:56 +08:00
Han
f5878bb397 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>
2026-06-04 09:48:50 +08:00
Han
0d7ee6c706 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'.
2026-06-04 09:48:44 +08:00
Han
c062bc5bd2 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
2026-06-04 09:48:27 +08:00
Claude
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
JazzuLu
e1ab103cd6 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
2026-05-28 10:28:26 +00:00
JazzuLu
3b6ac81104 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
2026-05-28 10:03:30 +00:00
JazzuLu
0f2cabc5e3 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
2026-05-28 09:57:59 +00:00
Claude
b220aeaec0 fix: feishu concurrency safety, error logging, Windows test compat (#1080)
Merge conflict resolved: combined getBotOpenID() getter (from #1080)
with quoted-content empty-message guards (from #1090).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:32:17 +08:00
cg33
f3647a3e5d Merge pull request #1083 from realraelrr/codex/appserver-stdio-url
fix(codex): preserve explicit stdio app-server URL
2026-05-27 23:30:32 +08:00
cg33
0f45c7df88 Merge pull request #1110 from woaillr-crypto/fix/opencode-yolo-skip-permissions
fix(opencode): skip permissions in yolo mode + macOS CheckLinger stub
2026-05-27 23:29:57 +08:00
cg33
04963074d1 Merge pull request #1116 from HuangYuChuh/fix/codex-honor-options-env
fix(codex): honor [projects.agent.options.env] from config.toml
2026-05-27 23:29:47 +08:00
kslex
5305c78403 fix(opencode): correct sessionID location and step_finish handling
- Fix handleStepStart: prefer sessionID from top-level JSON field, fallback to part
- Fix handleStepFinish: send EventResult when reason=stop, not when tool-calls
- Add resultSent atomic.Bool to prevent duplicate EventResult
- Add unit tests with JSON string construction style matching existing tests
This fixes empty response issue when opencode uses tools (issue #1094, PR #697)
2026-05-27 17:39:10 +08:00
JazzuLu
1345248a74 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
2026-05-26 15:36:47 +00:00
JazzuLu
abbbaa0dc6 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
2026-05-26 14:26:57 +00:00