299 Commits

Author SHA1 Message Date
程序员阿江(Relakkes)
5f0ddaecb2 fix: keep worktree session metadata after CLI init
Worktree sessions briefly showed the expected footer badge and then reverted because the CLI init path produced a second transcript under the actual worktree cwd. The desktop placeholder still held the repository launch metadata, but the startup cleanup removed that placeholder after writing metadata through a lookup that could target the stale source transcript. The runtime session also kept the launch cwd instead of the init cwd.

This moves session metadata writes to the transcript matching the CLI init cwd, carries repository launch metadata across duplicate session files, and updates the live ConversationService workDir when the init event reports the real cwd.

Constraint: Native CLI worktree creation happens inside the CLI after desktop has already created a placeholder session.

Rejected: Patch the footer to remember the first worktree badge | it would hide stale backend state and leave other session APIs on the source checkout.

Confidence: high

Scope-risk: narrow

Directive: Treat the CLI init cwd as authoritative for active desktop sessions; do not let placeholder cleanup discard repository launch metadata.

Tested: bun test src/server/__tests__/sessions.test.ts --test-name-pattern worktree|git-info|placeholder

Tested: cd desktop && bun run lint

Tested: cd desktop && bun run test -- src/components/shared/ProjectContextChip.test.tsx

Tested: git diff --check
2026-05-08 18:24:16 +08:00
程序员阿江(Relakkes)
3794a9d9ef fix: surface worktree identity in session badge
The footer project chip previously kept showing only the source project and selected branch even after a session launched inside an isolated CLI worktree. That made an active worktree session look identical to a normal checkout, especially while agent tools were already operating under .claude/worktrees. The server now returns explicit worktree metadata from the session launch intent, and the desktop chip preserves the user-facing project and branch while appending the isolated worktree slug.

Constraint: CLI worktree branches are internal implementation details and should not replace the user-selected branch label.

Rejected: Show only the actual worktree git branch | it would expose worktree-desktop-* internals and make the business branch harder to read.

Confidence: high

Scope-risk: narrow

Directive: Keep normal checkout footer rendering unchanged; only add worktree identity when session metadata says isolation is enabled.

Tested: bun test src/server/__tests__/sessions.test.ts --test-name-pattern git-info

Tested: cd desktop && bun run test -- src/components/shared/ProjectContextChip.test.tsx

Tested: cd desktop && bun run lint

Tested: git diff --check
2026-05-08 18:08:30 +08:00
程序员阿江(Relakkes)
678ba18a6f fix: keep session git badge on the active CLI checkout
The chat footer previously read git-info from the persisted session file and refreshed only on tab changes. Repository launches can update the active CLI cwd after the composer has already rendered, so the footer could keep showing an older selected branch even while the running model was operating in the correct checkout.

Constraint: The active CLI process is the source of truth for a live session cwd
Rejected: Derive the footer branch only from persisted session metadata | metadata can lag behind startup and does not prove the current running cwd
Confidence: high
Scope-risk: narrow
Tested: bun test src/server/__tests__/sessions.test.ts --test-name-pattern "git-info should prefer"
Tested: cd desktop && bun run lint
Tested: git diff --check
2026-05-08 18:02:12 +08:00
程序员阿江(Relakkes)
95b181dea2 feat: align desktop repository sessions with CLI worktrees
Desktop repository launches now defer isolated worktree creation until the
first user turn so the CLI owns worktree setup, cwd initialization, and
session metadata. The chat UI surfaces the pre-startup Git phase so users see
when a session is creating a worktree or switching a branch before model
output begins.

Constraint: Desktop must preserve the selected source checkout until a user actually sends a message
Constraint: CLI setup is the canonical owner for worktree creation and cwd initialization
Rejected: Create the worktree eagerly in the desktop session picker | it diverges from CLI session startup and creates worktrees before a conversation exists
Confidence: high
Scope-risk: moderate
Directive: Keep repository session startup routed through CLI worktree flags; do not reintroduce eager desktop worktree creation without testing transcript cwd and cleanup behavior
Tested: bun test src/server/__tests__/sessions.test.ts src/server/__tests__/conversation-service.test.ts
Tested: bun test src/server/__tests__/conversations.test.ts
Tested: bun test src/server/__tests__/conversations.test.ts --test-name-pattern "worktree startup status"
Tested: cd desktop && bun run test -- src/pages/EmptySession.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: git diff --check
Tested: CLI init-only native worktree smoke from feature/rail
Tested: agent-browser UI flow with MiniMax-M2.7-highspeed in a /tmp repository
2026-05-08 16:46:51 +08:00
程序员阿江(Relakkes)
6e5dd94dad Stop bearer providers from inheriting local API keys
Desktop Anthropic-compatible relay providers use ANTHROPIC_AUTH_TOKEN for
Authorization, but the CLI process can still load a stale ANTHROPIC_API_KEY
from inherited env, original settings, keychain-backed config, or the SDK
constructor fallback. That made Provider Test pass while real sessions sent
both Authorization and x-api-key to relays such as Packy and Shengsuanyun,
which then rejected the request as an invalid token/key.

The client now avoids falling back to a local API key when bearer-token
provider auth is active. Provider-managed auth_token env also writes an empty
ANTHROPIC_API_KEY so cc-haha settings explicitly override stale original
settings during desktop/sidecar startup. Regression tests pin both the SDK
client behavior and the desktop child-env behavior.

Constraint: Anthropic-compatible relay providers can reject mixed Authorization plus x-api-key headers even when direct provider tests pass
Rejected: Treat this as a provider/model-name issue | local proxy captures showed the failing request shape before provider handling
Rejected: Rely only on client.ts fallback suppression | settings/env layering can leave ANTHROPIC_API_KEY populated before the client is constructed
Confidence: high
Scope-risk: moderate
Directive: Bearer-token provider sessions must keep Authorization without inheriting or reintroducing x-api-key from user/global settings
Tested: bun test src/services/api/client.test.ts
Tested: bun test src/server/__tests__/providers.test.ts src/server/__tests__/providers-real.test.ts src/server/__tests__/conversation-service.test.ts
Tested: bun run check:server
Tested: Source and packaged sidecar proxy captures with stale original ANTHROPIC_API_KEY showed Authorization=true and x-api-key=false after the fix
Tested: desktop/scripts/build-macos-arm64.sh
Tested: PackyCodex2ccCustom and 胜算云 packaged-sidecar live calls returned ok
Not-tested: Full manual UI click-through in the rebuilt macOS app window
2026-05-08 15:20:45 +08:00
程序员阿江(Relakkes)
a31b3045fd Preserve explicit desktop runtime selection
Desktop sessions can prewarm before the user-selected runtime reaches the server, and an empty-session draft could previously persist an inferred default runtime as if the user had explicitly selected it. The fix keeps new-session defaults implicit while preserving explicit draft selections, and waits for queued runtime restarts before the first turn is delivered to the CLI process.

Constraint: Runtime selection is session-scoped and may arrive while prewarm or first-turn startup is already in flight

Rejected: Always persist the current default provider/model into new sessions | this masks whether the user actually selected a runtime and can launch stale providers

Confidence: high

Scope-risk: moderate

Directive: Do not send user turns across pending runtime restarts without re-checking the session runtime override

Tested: bun test src/server/__tests__/conversations.test.ts

Tested: cd desktop && bun run test -- src/pages/EmptySession.test.tsx

Tested: git diff --check
2026-05-08 13:45:02 +08:00
程序员阿江(Relakkes)
c9cc5e68a6 Merge IM deleted-session recovery into main
The detached worktree fix has been verified on adapter and server lanes
and is now integrated into the local main branch without pushing.

Constraint: main already contains follow-up local commits beyond the worktree base
Confidence: high
Scope-risk: moderate
Tested: bun test common/__tests__/session-store.test.ts common/__tests__/ws-bridge.test.ts
Tested: bun test src/server/__tests__/websocket-handler.test.ts src/server/__tests__/sessions.test.ts --timeout 30000
Tested: cd adapters && bunx tsc --noEmit
Tested: bun run check:adapters
Tested: bun run check:server
Not-tested: bun run verify fails on pre-existing agent-utils coverage ratchet; changed-line coverage is 95.92% and affected lanes pass
Related: 1f62bcd
2026-05-08 09:58:42 +08:00
程序员阿江(Relakkes)
1f62bcd919 Prevent IM chats from reusing deleted desktop sessions
Deleting a desktop session removed the transcript but left IM adapter
chat mappings and live WebSocket state able to point at the old session.
The server now closes the active session socket and removes adapter
mappings after deletion, while adapters refresh the shared session store
before reads so a running process cannot reuse stale in-memory data.

Constraint: Adapter session mappings are shared through adapter-sessions.json across long-running IM processes
Rejected: Patch each adapter ensureSession path separately | shared store refresh fixes all current adapters and avoids drift
Confidence: high
Scope-risk: moderate
Directive: Do not cache adapter session mappings without invalidating after server-side session deletion
Tested: bun test common/__tests__/session-store.test.ts common/__tests__/ws-bridge.test.ts
Tested: bun test src/server/__tests__/websocket-handler.test.ts src/server/__tests__/sessions.test.ts --timeout 30000
Tested: cd adapters && bunx tsc --noEmit
Tested: bun run check:adapters
Tested: bun run check:server
Not-tested: bun run verify fails on pre-existing agent-utils coverage ratchet; changed-line coverage is 95.92% and affected lanes pass
Related: https://github.com/NanmiCoder/cc-haha/issues/305
2026-05-08 09:58:24 +08:00
程序员阿江(Relakkes)
7696e21dc2 Support provider runtimes for scheduled tasks
Scheduled tasks used the model selector in model-only mode, so a task could store a third-party model id without the provider runtime needed to execute it. The desktop task editor now stores the selected provider with the model, and the scheduler injects the same provider-scoped runtime env that desktop sessions use before launching the sidecar.

Constraint: Scheduled tasks run outside an active desktop websocket session, so provider runtime must be serialized on the task itself.
Rejected: Reuse session runtime localStorage for tasks | scheduled executions can run long after the UI session is gone.
Confidence: high
Scope-risk: moderate
Directive: Keep task execution provider env isolated from inherited process env; stale parent ANTHROPIC_* values must not override task provider choices.
Tested: cd desktop && bun run test -- src/components/tasks/NewTaskModal.test.tsx src/components/controls/ModelSelector.test.tsx
Tested: bun test src/server/__tests__/scheduled-tasks.test.ts src/server/__tests__/cron-scheduler-launcher.test.ts
Tested: bun run check:desktop
Tested: bun run check:server
Tested: git diff --check
Not-tested: Live third-party provider API call; covered by sidecar launch integration with provider proxy env.
2026-05-08 09:49:16 +08:00
程序员阿江(Relakkes)
57a77453ed fix: isolate desktop provider runtimes per session
Desktop sessions can run against different saved providers at the same time, so the runtime selection must remain scoped to the session from WebSocket startup through the CLI request path. This adds parallel-session regression coverage, a browser-driven fake-provider E2E, and refreshes idle connected sessions after provider saves so stale provider edits are reapplied without disturbing active turns.

Constraint: Desktop provider credentials must stay session-scoped and must not leak across concurrent CLI child processes
Rejected: Rely on provider test connectivity alone | it does not exercise the desktop WebSocket, session runtime, or CLI request path
Confidence: high
Scope-risk: moderate
Directive: Do not change runtime selection persistence or provider env injection without rerunning the parallel provider browser E2E
Tested: cd desktop && bun run test src/stores/providerStore.test.ts src/stores/chatStore.test.ts
Tested: CLAUDE_CONFIG_DIR=/Users/nanmi/.claude bun test src/server/__tests__/conversations.test.ts --timeout 30000
Tested: desktop/scripts/e2e-parallel-providers-agent-browser.sh
Tested: bun run quality:smoke --provider-model custom:main:custom-main --provider-model minimax:main:minimax-main
Tested: cd desktop && bun run lint
Tested: git diff --check
Not-tested: bun run verify passes fully; coverage lane still fails on the existing agent-utils ratchet below baseline
2026-05-08 08:53:05 +08:00
程序员阿江(Relakkes)
64913c9242 fix(desktop): prevent config restarts from masquerading as turns
Runtime and permission changes can require a CLI restart, but the desktop UI should not interpret that maintenance restart as an active assistant turn. The restart path now stays out of the running chat state while preserving the stop/start behavior that applies model and bypass-permission changes.

Constraint: bypassPermissions changes require a CLI restart so startup args are applied.
Rejected: Hide the stop button in the frontend | the backend would still conflate configuration restarts with agent turns and quick-send races would remain untested.
Confidence: high
Scope-risk: narrow
Directive: Keep runtime and permission restart transitions serialized before user_message handling.
Tested: bun test src/server/__tests__/conversations.test.ts -t "in-flight runtime restart|in-flight permission restart"
Tested: bun run check:server
Not-tested: Browser screenshot; this change is the WebSocket state contract, not layout rendering.
2026-05-07 19:44:08 +08:00
程序员阿江(Relakkes)
fd5dc097a7 fix: isolate desktop session streaming state
Desktop chat sessions can stream and reconnect concurrently, so shared in-process buffers must not be keyed only by process lifetime. This change scopes streaming delta buffers, task-tool refresh bookkeeping, and CLI task mutations to the session that produced the event. It also ignores stale client socket closes after a newer socket has replaced the active connection for the same session.

Constraint: Desktop users can keep multiple sessions and tabs active at the same time.
Rejected: Serialize all desktop streaming through one active session | would hide the race instead of preserving multi-session behavior.
Confidence: high
Scope-risk: moderate
Directive: Do not reintroduce process-global chat/task pending state without session keys and multi-session regression tests.
Tested: cd desktop && bun run test -- src/stores/chatStore.test.ts src/stores/cliTaskStore.test.ts
Tested: bun test src/server/__tests__/websocket-handler.test.ts
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
Tested: bun run check:server
Tested: bun run check:coverage | changed-lines 100%, fails only existing agent-utils baseline
Tested: bun run verify | 8 passed, 1 failed on existing agent-utils coverage baseline, 2 skipped
Not-tested: Real desktop dual-window manual smoke.
Related: https://github.com/NanmiCoder/cc-haha/issues/302
Related: https://github.com/NanmiCoder/cc-haha/issues/303
2026-05-07 18:33:57 +08:00
程序员阿江(Relakkes)
165d914d5a fix: launch scheduled tasks through desktop sidecar
Scheduled task Run Now was still constructing a source checkout Bun command, so packaged desktop builds could try to execute src/entrypoints/cli.tsx from a missing or wrong root. Resolve the same launcher used by the desktop runtime first, and keep the source checkout fallback only for development.

Constraint: Desktop Release tasks must run through the configured sidecar and app root instead of assuming source files exist on disk

Rejected: Retain import.meta.dir path math with broader fallback | still bypasses packaged desktop launcher and repeats the issue root cause

Confidence: high

Scope-risk: narrow

Directive: Do not change scheduled task execution back to direct source CLI invocation without repeating desktop Run Now E2E

Tested: bun test src/server/__tests__/cron-scheduler-launcher.test.ts src/server/__tests__/cron-scheduler.test.ts

Tested: bun run check:server

Tested: bun run check:native

Tested: Desktop UI E2E via scheduled task page create task and Run Now with fake sidecar

Not-tested: Full packaged macOS .app click test
2026-05-07 18:32:38 +08:00
程序员阿江(Relakkes)
8b07c16f45 fix: keep startup failures visible in terminals
Diagnostics should capture fatal server failures without replacing the terminal stderr signal that developers rely on during local startup. Fatal uncaught exceptions now print their stack to stderr, persist the diagnostic event, and exit non-zero so repeated server starts expose port conflicts immediately.

Constraint: Startup diagnostics must still write sanitized runtime events for export bundles.
Rejected: Only document checking runtime-errors.log | developers should not lose the standard stderr failure path.
Confidence: high
Scope-risk: narrow
Directive: Do not install process-level exception handlers that swallow fatal startup errors without preserving stderr and non-zero exit behavior.
Tested: bun test src/server/__tests__/diagnostics-service.test.ts
Tested: bun run check:server
Tested: SERVER_PORT=3456 bun run src/server/index.ts returned exit=1 and printed the port-conflict stack while diagnostics recorded the event
2026-05-07 16:50:20 +08:00
程序员阿江(Relakkes)
7fbce35be6 fix: prevent malformed generated session titles
Session titles need to appear immediately, but the async AI title pass can return fenced or escaped JSON fragments. Keep the first-message title path fast, preserve optimistic client titles during background refresh, and only accept structured title responses that parse cleanly.

Constraint: Desktop sessions should stop showing Untitled/New Session after the first user turn.
Rejected: Accept short raw model output as a fallback | malformed JSON fragments are short enough to leak into the UI.
Confidence: high
Scope-risk: moderate
Directive: Do not loosen generated title parsing without regression coverage for fenced, escaped, and truncated JSON responses.
Tested: bun test src/server/__tests__/title-service.test.ts
Tested: bun run check:server
Tested: cd desktop && bun run test -- --run src/stores/chatStore.test.ts src/stores/sessionStore.test.ts src/pages/EmptySession.test.tsx
Tested: agent-browser smoke on http://127.0.0.1:1420/ confirmed sidebar and tab titles update without JSON fragments.
2026-05-07 16:28:08 +08:00
程序员阿江(Relakkes)
7ae885a114 fix: add safe Doctor rescue path for desktop upgrades
Online upgrades can strand users on stale desktop UI state or malformed local persistence. This adds a deny-by-default Doctor path that resets only regenerable desktop UI state, reports protected local files with redacted metadata, and keeps protected repair as a dry-run no-op until a reviewed backup-first flow exists.

Constraint: Chat transcripts, model/provider config, Skills, MCP, IM bindings, adapter sessions, OAuth tokens, plugins, and team/session records are user-owned protected state.
Rejected: Automatically rewrite malformed protected JSON | unsafe without schema-specific migrations and backups.
Rejected: Continue relying only on startup migrations | users need an explicit recovery action after a white screen.
Confidence: high
Scope-risk: moderate
Directive: Keep Doctor repair deny-by-default; do not mutate protected state without an explicit reviewed backup-first manual repair flow.
Tested: bun test src/server/__tests__/doctor-service.test.ts
Tested: cd desktop && bun run test src/components/ErrorBoundary.test.tsx src/lib/doctorRepair.test.ts src/__tests__/diagnosticsSettings.test.tsx src/components/layout/StartupErrorView.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:server
Tested: bun run verify (failed only existing agent-utils coverage baseline; changed-lines coverage 97.62%)
Not-tested: Packaged desktop manual Doctor click path.
2026-05-07 00:04:06 +08:00
程序员阿江(Relakkes)
fa47adc33a fix: prevent upgrade crashes from stale persistence
Desktop users can carry provider indexes, managed settings, localStorage state, and native update state from builds that no longer match current readers. This adds startup migrations and recovery paths before server and React state are consumed, plus a persistence upgrade gate so future storage protocol changes ship with old-format fixtures.

Constraint: Existing installs may contain malformed or legacy JSON/localStorage that must not block startup.
Constraint: Local verify should evaluate the current worktree diff rather than unrelated detached-worktree history.
Rejected: Treat invalid persisted state as fatal | reproduces white-screen and startup failure behavior for existing users.
Rejected: Bypass PR policy locally | hides real gate behavior and does not fix detached-worktree false positives.
Confidence: high
Scope-risk: moderate
Directive: Any local JSON, localStorage, or app config shape change must add a migration fixture and keep `bun run check:persistence-upgrade` green.
Tested: bun run check:persistence-upgrade; bun run check:policy; bun run check:desktop; bun run check:server; bun run check:native; bun run verify (9 passed, 1 coverage baseline failure)
Not-tested: Live provider baseline; existing user configs beyond covered fixtures
2026-05-06 23:20:21 +08:00
程序员阿江(Relakkes)
b156be8d8d feat: make PR quality verification self-enforcing
Contributors and coding agents need one local command that both reports and enforces the quality contract. This change turns the PR gate into the shared verification entrypoint, adds path-selected local lanes, tightens coverage accounting around changed lines, and documents the repair loop in contributor and agent-facing guidance.

Constraint: Ordinary PR verification must stay non-live and runnable without provider credentials
Constraint: Coverage policy updates in this commit require maintainer approval before push/merge
Rejected: Keep quality guidance only in docs | agents need executable scripts and AGENTS.md instructions to follow the loop consistently
Confidence: high
Scope-risk: broad
Directive: Do not bypass `bun run verify` for production changes; fix failed lanes and coverage reports instead of lowering thresholds
Tested: bun run check:policy
Tested: ALLOW_CLI_CORE_CHANGE=1 ALLOW_COVERAGE_BASELINE_CHANGE=1 bun run verify
Not-tested: live provider baseline; no provider credentials were required for this non-live PR gate
2026-05-06 22:33:43 +08:00
程序员阿江(Relakkes)
9719726cd2 feat: make quality gates observable and enforceable
The repository now has a measurable PR quality path instead of a loose set of
manual checks. Coverage, quarantine governance, provider smoke, desktop smoke,
and workflow wiring all produce durable reports that contributors and maintainers
can inspect without reconstructing terminal output.

This also fixes the desktop smoke current-runtime path so browser-driven smoke
runs use the desktop default active provider instead of forcing the official
current model, and records that runtime decision as an artifact.

Constraint: Default PR gates must remain non-live and contributor-safe while live model checks stay explicit.
Constraint: Release packaging is still GitHub Actions based, so release preflight must run before the build matrix.
Rejected: Make live provider or desktop smoke mandatory on every PR | secrets, quotas, and model availability are maintainer-controlled.
Rejected: Let PRs lower coverage baselines in the same change | base-branch ratchet comparison must remain authoritative.
Confidence: high
Scope-risk: moderate
Directive: Do not relax coverage or quarantine policy without a maintainer approval label and a fresh quality report.
Tested: ALLOW_CLI_CORE_CHANGE=1 ALLOW_COVERAGE_BASELINE_CHANGE=1 bun run quality:gate --mode pr
Tested: bun run quality:gate --mode baseline --allow-live --only provider-smoke:* --provider-model nvidia-custom:main:nvidia-custom-main --artifacts-dir /tmp/quality-gate-live-smoke
Tested: bun run quality:gate --mode baseline --allow-live --only desktop-smoke:* --provider-model current:current:current-runtime --artifacts-dir /tmp/quality-gate-desktop-smoke-fixed
Tested: git diff --check
Not-tested: Full live release mode with multiple providers in hosted CI; provider credentials and quota remain maintainer-controlled.
2026-05-06 16:25:10 +08:00
程序员阿江(Relakkes)
f262ec3029 feat: protect desktop branch launches with worktree isolation
Desktop sessions now resolve repository launch intent before creation, so users can pick a branch, choose whether to isolate it in a worktree, and get stable error messages instead of silent branch-switch failures. The server owns the Git safety checks and session metadata so the UI and real agent runtime agree on the actual working directory.

Constraint: Direct branch switching must not overwrite or hide uncommitted user changes
Constraint: Desktop worktree branches must stay out of normal branch selection and recent-project labels
Rejected: Let the UI call git directly | server-side checks keep session metadata and runtime launch paths consistent
Rejected: Auto-switch dirty checkouts | users need an explicit isolated-worktree choice to protect local edits
Confidence: high
Scope-risk: moderate
Directive: Do not relax dirty-worktree or checked-out-branch guards without adding equivalent business-flow tests
Tested: ALLOW_CLI_CORE_CHANGE=1 bun run quality:pr
Tested: /tmp business-flow script with dirty checkout, checked-out branch, isolated worktree, missing branch, non-git, missing directory, and real LLM session
Tested: agent-browser desktop UI flow across dirty, checked-out, non-git, branch search, recent-project, and Run scenarios
2026-05-06 14:51:46 +08:00
程序员阿江(Relakkes)
578a967c5a Merge commit '13b765b5e94fe08009d04bdbce2195d084a4b894' 2026-05-06 11:57:12 +08:00
程序员阿江(Relakkes)
13b765b5e9 Expose built-in workflow agents outside internal experiments
External builds were inheriting internal feature-gate defaults, so Explore,
Plan, and verification disappeared from the active agent registry. Keep the
internal ant experiment behavior gated, but make public builds default to the
full workflow agent set while preserving the SDK opt-out path.

Constraint: Internal ant builds still rely on GrowthBook rollout gates.
Rejected: Force-enable all users unconditionally | would bypass internal experiment controls.
Confidence: high
Scope-risk: narrow
Directive: Do not move public built-in agents behind internal-only feature flags without verifying desktop /api/agents and real Agent subagent orchestration.
Tested: bun test src/tools/AgentTool/builtInAgents.test.ts
Tested: git diff --check
Not-tested: Full quality gate in this commit step; earlier quality:pr is blocked by cli-core approval policy.
2026-05-06 11:56:59 +08:00
程序员阿江(Relakkes)
7e369ab7c7 Merge commit '147d060' 2026-05-06 11:44:12 +08:00
程序员阿江(Relakkes)
147d060004 fix: preserve custom provider thinking settings
Custom providers can point at user-defined model IDs that the CLI cannot
classify by built-in model tables. Declare the existing tier capability
overrides for custom provider roles so explicit thinking and effort settings
survive request construction.

Constraint: Issue #285 reports local proxy logs dropping user-defined model thinking and effort as passthrough with no config.
Rejected: Disable model capability checks globally | would relax behavior for built-in presets and non-custom providers.
Confidence: high
Scope-risk: narrow
Directive: Keep this scoped to custom providers unless each preset has explicit capability semantics.
Tested: bun test src/server/__tests__/providers.test.ts src/server/__tests__/provider-presets.test.ts src/utils/__tests__/thinking.test.ts
Tested: bun run check:server
Tested: bun run quality:pr
Tested: bun run quality:gate --mode baseline --allow-live --provider-model custom:main:custom-main
Tested: agent-browser custom provider UI smoke with request log showing thinking adaptive and effort max
Related: https://github.com/NanmiCoder/cc-haha/issues/285
2026-05-06 11:44:03 +08:00
程序员阿江(Relakkes)
c0fe61b665 Merge commit '1cd90dc' 2026-05-06 11:40:59 +08:00
程序员阿江(Relakkes)
1cd90dc66a feat: let users opt out of bundled Computer Use
Computer Use is useful when explicitly needed, but exposing its MCP tools by default creates unnecessary desktop-control surface for users who want coding-only sessions. This adds a shared disable path for CLI flags, environment, and desktop settings while keeping preauthorized app state in one config file.

The same change also preserves Windows and WSL shell startup behavior by applying the MSYS argument-conversion guard only on WSL-bound launches.

Constraint: Computer Use MCP must not be exposed to the Coding Agent when disabled

Constraint: Desktop settings and CLI sessions need to read the same persisted Computer Use config

Rejected: Environment-only disable switch | desktop users need a persistent Settings control

Rejected: Remove Computer Use setup entirely | enabled sessions still need the existing built-in MCP path

Confidence: high

Scope-risk: moderate

Directive: Keep every new Computer Use entrypoint wired through loadStoredComputerUseConfig or the CLI disable flag before adding MCP tools

Tested: bun test src/utils/computerUse/gates.test.ts src/utils/computerUse/preauthorizedConfig.test.ts src/server/__tests__/computer-use-api.test.ts src/utils/shell/wslInterop.test.ts desktop/src/pages/ComputerUseSettings.test.tsx

Tested: bun run check:server; bun run check:desktop; bun run check:docs; bun run check:policy; bun run check:native; git diff --check

Tested: SKIP_INSTALL=1 ./desktop/scripts/build-macos-arm64.sh; codesign verify; hdiutil verify; built CLI Computer Use E2E exposure and disable checks

Not-tested: Full screenshot/control action after granting macOS Screen Recording permission on this machine
2026-05-06 11:40:49 +08:00
程序员阿江(Relakkes)
f9f1f20e99 Fix local proxy tool calls for real provider responses
Local OpenAI-compatible proxies can return function arguments as parsed objects instead of JSON strings. Preserve object-shaped arguments directly and serialize them for streaming deltas so Write, Bash, and Edit tool calls keep the fields required by Anthropic tool validation.

Constraint: Local proxy implementations such as OneAPI/NewAPI may not preserve OpenAI's string-only arguments shape.
Rejected: Normalize every upstream response through JSON.stringify before parsing | loses already-valid object identity and leaves streaming object deltas vulnerable to [object Object].
Confidence: high
Scope-risk: narrow
Directive: Do not assume function.arguments is always a string on provider responses or stream deltas.
Tested: bun test src/server/__tests__/proxy-streaming.test.ts src/server/__tests__/proxy-transform.test.ts
Tested: bun run check:server
Tested: bun run check:native
Tested: bun run quality:pr
Tested: agent-browser with real Ollama qwen3:4b provider for Write/Bash/Edit and streaming Write
Not-tested: Real Windows OneAPI/NewAPI instance from the issue reporters was not available locally.
2026-05-06 11:39:10 +08:00
程序员阿江(Relakkes)
b72bca94e3 fix: wait for sdk socket before context inspection
Desktop context inspection could send get_context_usage while a prewarmed CLI process existed but before the SDK socket was connected. That first control request sat in the pending outbound queue and could time out, leaving the composer spinner or a misleading empty-state context display. The server now waits for the SDK socket before sending control requests, and the UI renders the actual initial context snapshot instead of masking empty active-session data.

Constraint: CLI /context and desktop get_context_usage must stay on the shared collectContextData/analyzeContextUsage path

Rejected: Hide zero-token active snapshots in the component | that masks backend timing bugs and prevents showing real initial system/tool context

Confidence: high

Scope-risk: narrow

Directive: Do not queue control requests before the SDK socket is connected; let user messages keep the pending outbound behavior

Tested: bun test src/server/__tests__/conversations.test.ts --test-name-pattern "not queue control|context-only|prewarmed empty session|structured session inspection"

Tested: cd desktop && bun run test -- pages.test.tsx --test-name-pattern "EmptySession shows draft context|first-paint spinner|empty live session|live context usage|runtime model"

Tested: bun run check:server

Tested: cd desktop && bun run lint

Tested: real dev API prewarmed empty session returned 31,190 / 262,144 (12%) on first context-only inspection and 16ms on repeat

Tested: browser at http://127.0.0.1:5174/ showed 上下文用量 12% for an empty active session
2026-05-05 20:10:04 +08:00
程序员阿江(Relakkes)
1e5bd47fe6 Merge commit '622b94011ff962fc80f010d98b4dab9132834878' 2026-05-05 19:59:03 +08:00
程序员阿江(Relakkes)
1029c9e7bc fix: align transcript context fallback with cli totals
The live desktop context path already routes through the CLI get_context_usage control request and the shared analyzeContextUsage implementation. The offline transcript fallback was still using its own prompt-token-only estimate, so disconnected sessions could report a lower context total than the live /context path. The fallback now reuses the same current-context total helper and includes output tokens as next-turn context.

Constraint: Desktop must still show context estimates when the CLI process is not running

Rejected: Keep transcript fallback prompt-only | it diverges from the live CLI /context total and can drop after responses

Confidence: high

Scope-risk: narrow

Directive: Transcript context fallback must stay aligned with calculateCurrentContextTokenTotal

Tested: bun test src/server/__tests__/conversations.test.ts --test-name-pattern "context-only|structured session inspection|reconstruct Sonnet 4.6 transcript usage"

Tested: bun test src/utils/__tests__/context.test.ts

Tested: bun run check:server
2026-05-05 19:52:48 +08:00
程序员阿江(Relakkes)
f02fe83e28 fix: keep context usage from dropping after responses
Context inspection was switching from the local context estimate to the latest
provider usage total once a response completed. That provider total omitted the
assistant output tokens, even though those tokens become part of the next turn's
context, so the desktop meter could fall from 11% to 10% after work finished.
The context total now includes output tokens and keeps the local estimate as a
lower bound.

Constraint: Provider usage and local context estimates use different token accounting paths
Rejected: Trust provider input tokens alone | it omits the latest assistant output from the next-turn context
Confidence: high
Scope-risk: narrow
Directive: Context usage totals must represent the next-turn conversation context, not billing-only input tokens
Tested: bun test src/utils/__tests__/context.test.ts
Tested: bun run check:server
2026-05-05 19:42:06 +08:00
程序员阿江(Relakkes)
71f851d60a fix: clear DingTalk bot credentials through explicit unbind
DingTalk bot unbind was routed through the generic adapter config update,
but undefined credential fields are dropped during JSON serialization. That
left stored Client ID and Secret values intact after clicking the unbind
button. Match the working WeChat path with a dedicated server endpoint and
frontend API call so credential removal is explicit.

Constraint: JSON request bodies cannot preserve undefined fields for generic config clearing
Rejected: Keep using updateConfig with undefined fields | serialized requests omit the fields before the server can clear them
Confidence: high
Scope-risk: narrow
Directive: Keep credential-clearing flows on explicit unbind endpoints rather than relying on partial config merges
Tested: bun test src/server/__tests__/adapters.test.ts
Tested: cd desktop && bun run test src/stores/adapterStore.test.ts
Tested: bun run check:desktop
Tested: bun run check:server
Not-tested: bun run quality:pr is blocked by repository policy requiring allow-cli-core-change approval for the broader branch impact
2026-05-05 19:30:43 +08:00
程序员阿江(Relakkes)
ac342f4bcd Merge commit 'e4f9825bc116e88487d3c479e4e7afc1ec3a34fe' 2026-05-05 18:26:05 +08:00
程序员阿江(Relakkes)
e4f9825bc1 fix: avoid misleading context loading on empty desktop sessions
The desktop composer now treats draft and not-yet-running sessions as pending
until a real CLI context snapshot exists. Context inspection has a lightweight
context-only path so the composer and /context panel do not wait on unrelated
usage or MCP status work, and desktop boot no longer blocks the first shell
render on tab restoration.

Constraint: Empty composer state has no live CLI context to inspect until a session starts
Rejected: Display 0% before live context exists | it implied one user message consumed the fixed prompt/tool baseline
Confidence: high
Scope-risk: moderate
Directive: Do not show numeric context usage without a real context snapshot
Tested: cd desktop && bun run test -- pages.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
Tested: bun run check:server
Tested: Browser reload at http://127.0.0.1:5174 with cleared open-tabs showed pending context and no /inspection request
2026-05-05 18:25:53 +08:00
程序员阿江(Relakkes)
851b33ab70 Merge actionable diagnostics logging into main
Bring the runtime diagnostics worktree back onto local main while preserving the existing local main commits for provider context windows and IM localization.

Constraint: Preserve both independent local main commits and the diagnostics worktree commit.
Confidence: high
Scope-risk: moderate
Directive: Keep diagnostics capture non-blocking and sanitized when modifying this area again.
Tested: merged cleanly on local main after prior check:server, check:desktop, and agent-browser diagnostics export verification
2026-05-05 17:59:46 +08:00
程序员阿江(Relakkes)
f2437bf724 feat: Make diagnostics actionable for runtime failures
Diagnostics exports previously preserved only compact summaries, which made user-uploaded issue bundles hard to debug. This records richer sanitized details from server, CLI, SDK, browser, React, and desktop API failure paths while keeping request bodies and secrets out of client-side reports.

Constraint: Diagnostic bundles must be useful for GitHub issues without including chat contents, file contents, full environments, or API keys.
Rejected: Only expand the Settings UI summary | the exported bundle would still miss hidden runtime failures.
Confidence: high
Scope-risk: moderate
Directive: Keep diagnostics write paths best-effort and non-blocking; do not add request-body capture without a redaction review.
Tested: bun test src/server/__tests__/diagnostics-service.test.ts src/server/__tests__/conversation-service.test.ts
Tested: cd desktop && bun run test src/api/client.test.ts src/__tests__/diagnosticsSettings.test.tsx --run
Tested: bun run check:server
Tested: bun run check:desktop
Tested: agent-browser E2E on ports 37652/41752 captured client_unhandled_rejection and exported a redacted tar.gz bundle
2026-05-05 17:57:50 +08:00
程序员阿江(Relakkes)
4e20aac647 fix: raise featured Sonnet provider context windows
The featured Anthropic-compatible provider presets now advertise their Sonnet models as one-million-token windows so the desktop context form and runtime env match the requested provider limits. Regression assertions cover both preset display and runtime env generation.

Constraint: Only the two featured provider presets requested by the desktop settings flow should change.
Rejected: Change global Sonnet built-in default | would alter unrelated providers and custom models.
Confidence: high
Scope-risk: narrow
Directive: Do not lower these preset windows without checking provider-specific limits and the desktop settings preview.
Tested: bun test src/server/__tests__/provider-presets.test.ts src/server/__tests__/providers.test.ts
Tested: bun run check:server
Tested: agent-browser UI verification on http://127.0.0.1:49174 with backend http://127.0.0.1:49173
Not-tested: Live API requests against 接口AI or 胜算云.
2026-05-05 17:28:28 +08:00
程序员阿江(Relakkes)
2459488703 Harden provider auth, adapter paths, and notification retries
This captures the pending worktree fixes before applying them to the
current local main. The changes tighten IM adapter path and credential
handling, preserve retry behavior for failed desktop notifications, and
make Azure/OpenAI provider auth and stop reasons reflect actual runtime
state.

Constraint: Worktree was detached from an older local main with pending uncommitted fixes
Rejected: Merge the detached HEAD directly | would also replay unrelated stale history
Rejected: Leave notification dedupe as fire-and-forget | failed sends consumed retry keys
Confidence: high
Scope-risk: broad
Directive: Keep adapter absolute-path matching constrained to configured work roots
Tested: git diff --check
Not-tested: full quality gate before local main integration
2026-05-04 21:37:30 +08:00
程序员阿江(Relakkes)
8a81636757 Merge Azure OpenAI auth into local main
Remote main already contains PR #217. Local main had provider context-window and auth-strategy work, so this merge keeps both context resolvers and reconciles the desktop Bun lockfile with the merged desktop package manifest. The accidental remote .nvimlog artifact is excluded from the merge result.

Constraint: Local main was 15 commits ahead and 8 commits behind origin/main after PR #217 was merged remotely
Rejected: Fast-forward pull | local main had unpushed commits
Rejected: Keep remote desktop lockfile verbatim | failed bun install --frozen-lockfile against the merged package.json
Confidence: high
Scope-risk: broad
Directive: Keep provider-configured context windows ahead of OpenAI OAuth model windows so explicit user/provider settings win
Tested: bun install --frozen-lockfile; cd desktop && bun install --frozen-lockfile; git diff --check; bun run check:server; bun run check:desktop; ALLOW_CLI_CORE_CHANGE=1 bun run quality:pr
Not-tested: live provider OAuth login with a real OpenAI account
2026-05-04 21:24:22 +08:00
程序员阿江(Relakkes)
472ff73927 Stabilize OpenAI auth PR quality gates
PR 217 combined OpenAI OAuth model options with env-configured provider models, but the picker path returned before appending third-party model aliases. The desktop workspace test also exercised Prism highlighting for every expanded line, which was costly enough to time out on CI runners. The docs job did not need the root React Vite plugin; the desktop package owns that dependency.\n\nConstraint: PR Quality must pass server, desktop, and docs jobs before merge.\nRejected: Increase Vitest timeout | keeps the expensive render path and hides the CI regression.\nRejected: Add root Vite 8 peer dependencies | root only builds VitePress docs; React Vite plugin belongs in desktop/.\nConfidence: high\nScope-risk: narrow\nTested: npm ci --ignore-scripts; npm run docs:build; bun test src/server/__tests__/settings.test.ts src/server/__tests__/conversation-service.test.ts; bun run check:server; bun run check:desktop\nNot-tested: live provider OAuth login
2026-05-04 21:10:08 +08:00
程序员阿江(Relakkes)
f1c5f86b80 feat: keep IM permission approvals consistent
DingTalk can receive interactive card callbacks, but the card UI still depends on a published template, so the adapter now supports a template-backed card path with text commands as the reliable fallback. Telegram and WeChat use the same allow-once, allow-always, and deny semantics so manual authorization behaves the same across platforms.

Constraint: DingTalk button rendering requires an operator-provided interactive card template id
Rejected: Treat the existing AI streaming card template as a permission card | it cannot guarantee visible action buttons
Confidence: high
Scope-risk: moderate
Directive: Do not remove the text approval fallback unless DingTalk card template provisioning is guaranteed
Tested: bun test adapters/common/__tests__/permission.test.ts adapters/dingtalk/__tests__/permission-card.test.ts adapters/telegram/__tests__/telegram.test.ts adapters/common/__tests__/config.test.ts src/server/__tests__/adapters.test.ts
Tested: bunx tsc -p adapters/tsconfig.json --noEmit
Tested: bun run check:adapters
Tested: cd desktop && bun run build
Tested: bun run check:server
Tested: bun run check:docs
Tested: git diff --check
Not-tested: bun run quality:pr is blocked by existing CLI core approval policy; see artifacts/quality-runs/2026-05-03T13-19-56-232Z/report.md
2026-05-04 19:03:36 +08:00
cynicalight
ff40028ae1 fix: desktop and more test 2026-05-04 17:57:03 +08:00
cynicalight
9204317307 fix: /context command to display the correct context window for gpt 2026-05-04 16:45:59 +08:00
cynicalight
9533c20d1d fix: model selection 2026-05-04 16:45:59 +08:00
cynicalight
2835426cf3 fix: enable the local apikey models while using openai auth subscription 2026-05-04 16:45:59 +08:00
cynicalight
24d31e284f fix: cli auth state verification 2026-05-04 16:45:24 +08:00
cynicalight
f091e8e5a5 feat: openai auth login via cli 2026-05-04 16:45:24 +08:00
程序员阿江(Relakkes)
2ca5228171 feat: make IM adapter behavior consistent
WeChat and DingTalk were using different pairing, attachment, and response
state paths, which made the new IM channels behave differently from Feishu
and Telegram. Align the shared pairing model, wire inbound media into the
existing attachment bridge, and map platform response capabilities to their
real APIs: WeChat block streaming plus typing, DingTalk AI Card streaming.

Constraint: WeChat iLink exposes typing and block streaming, but no editable message/card streaming API
Constraint: DingTalk streaming depends on the AI Card create/deliver/stream/finalize lifecycle
Rejected: Fake DingTalk typing with standalone markdown | it would add chat noise instead of platform state
Rejected: Auto-pair WeChat after QR login | it bypasses the shared IM pairing model
Confidence: high
Scope-risk: moderate
Directive: Keep WeChat streaming as block-send unless iLink adds editable messages; keep DingTalk streaming on AI Card APIs
Tested: bun run check:adapters; bun run check:server; cd desktop && bun run test src/stores/adapterStore.test.ts; cd desktop && bun run build; bunx tsc -p adapters/tsconfig.json --noEmit; git diff --check
Not-tested: Live WeChat and DingTalk platform smoke with real production credentials
2026-05-03 21:08:12 +08:00
程序员阿江(Relakkes)
6d9aa98022 Support DingTalk IM without blocking on project history
DingTalk uses QR registration to store client credentials, then reuses the existing IM pairing and session bridge. The merged main implementation keeps the existing WeChat QR binding path intact while adding DingTalk as a peer IM platform. The default IM workdir now falls back to the local user working directory so a newly bound chat can start immediately even when recent-project history is empty.

Constraint: Local main already carries WeChat IM, so the merge keeps WeChat config, QR binding, sidecar args, and unbind behavior intact while adding DingTalk.
Rejected: Keep empty defaultProjectDir as project-picker-only | newly bound IM users can hit a dead end with no recent projects.
Confidence: high
Scope-risk: moderate
Directive: Keep IM platform unions synchronized across config, pairing, sidecar args, desktop settings, and docs.
Tested: bun test common/ dingtalk/ wechat/; bun test src/server/__tests__/adapters.test.ts; cd adapters && bunx tsc --noEmit; bun run check:policy; bun run check:server; bun run check:desktop; bun run check:adapters; bun run check:native; bun run check:docs
Not-tested: quality:pr full gate was blocked by existing local main CLI-core diff requiring allow-cli-core-change maintainer approval; live post-fix DingTalk second-message delivery was not repeated after the merge.
2026-05-03 17:56:22 +08:00
程序员阿江(Relakkes)
99b343d6a1 Merge branch 'feat/wechat-im' 2026-05-03 17:42:31 +08:00