5 Commits

Author SHA1 Message Date
程序员阿江(Relakkes)
8c99efca20 Prevent destructive desktop actions from bypassing confirmation
The desktop settings and sidebar still had deletion flows that either used browser-native confirms or deleted immediately. This change consolidates destructive confirmations behind a shared dialog component, applies it to provider deletion, plugin uninstall, adapter unbind, and sidebar session deletion, and adds regression coverage so delete actions require an explicit second confirmation before mutating state.

Constraint: Other in-progress desktop work in the tree had to stay out of this commit
Constraint: Existing MCP and task confirmations needed to keep their current behavior
Rejected: Leave confirmations embedded per-page with browser dialogs | inconsistent UX and easy to regress
Rejected: Add confirmations only to provider deletion | leaves other destructive desktop flows unsafe
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Any new desktop delete, uninstall, or unbind action should use the shared ConfirmDialog instead of browser-native dialogs or one-click deletion
Tested: bun run test src/components/layout/Sidebar.test.tsx src/__tests__/generalSettings.test.tsx; bun run lint
Not-tested: Manual desktop click-through of every destructive action after this refactor
2026-04-22 17:30:59 +08:00
程序员阿江(Relakkes)
bfafd26fb6 fix: batch resolve 5 issues from Feishu bug tracker
- fix(desktop): Settings Agents/Skills page layout overflow at narrow widths
  Shift header grid breakpoint md→xl, summary cards sm→3col, add min-w-0/truncate

- fix(desktop): TabBar tab style — remove border-r separators, use bg-only active state
  Drop ::after indicator and inter-tab borders; active tab distinguished by surface bg

- feat(desktop): IM Adapters page — horizontal tabs with Feishu first, Telegram second
  Replace vertical stack with tablist; add ImTabButton with aria-selected + focus-visible

- fix(server): bundled IM session cwd resolves to / instead of selected project
  Root cause: preload.ts chdir(CALLER_DIR) inherits '/' from Tauri-spawned sidecar.
  Fix: pin CALLER_DIR and PWD to session workDir in conversationService spawn env.
  Add diagnostic logs at sessionService, ws/handler, and conversationService.

- fix(feishu): StreamingCard shows duplicate "thinking" indicators
  Merge static loading element into streaming_content; renderedText() controls state.

- test(adapters): add 5 ImageBlockWatcher edge-case unit tests (reset, relative path,
  multi-image chunk, malformed data URI)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 13:36:14 +08:00
程序员阿江(Relakkes)
3e3c2bc116 experiment(desktop): auto-spawn adapter sidecar on launch + restart on save
Wires the new claude-sidecar adapters mode into the actual desktop UX:

* On app launch, Tauri main process now spawns the adapter sidecar right
  after the server sidecar comes up. The sidecar reads ~/.claude/adapters.json
  and connects whichever of Feishu / Telegram has credentials configured;
  if neither does, it warns + skips + exits cleanly (treated as expected).
* When the user saves credentials in the existing AdapterSettings page,
  the frontend store invokes restart_adapters_sidecar after the PUT
  /api/adapters succeeds. Tauri kills the old child and spawns a new one,
  which picks up the fresh config and establishes the WebSocket connection
  to Feishu / Telegram immediately — no app restart needed.

End-to-end behavior is now: install app → open → configure credentials in
settings → click save → IM bot is live.

Implementation
==============

* desktop/src-tauri/capabilities/default.json: replace the stale
  binaries/claude-server allowlist with binaries/claude-sidecar across
  shell:allow-execute, shell:allow-spawn, plus a new shell:allow-kill
  entry needed for the restart path. (P2 changed externalBin to
  claude-sidecar but missed updating capabilities, which is why the prior
  bundle worked at all in dev mode but would have failed in production.)

* desktop/src-tauri/src/lib.rs:
  - new AdapterState that holds an Option<CommandChild>
  - start_adapters_sidecar() spawns `claude-sidecar adapters --feishu --telegram`
    with ADAPTER_SERVER_URL env var pointing at the dynamic server port
    (converted http://→ws:// since WsBridge does `new WebSocket(url)`
    directly without protocol translation)
  - spawn_and_track_adapters_sidecar() handles spawn + state insertion
  - stop_adapters_sidecar() kills + clears state
  - new #[tauri::command] restart_adapters_sidecar that calls stop+spawn
  - sidecar Terminated events are info-logged, not treated as errors,
    so the credential-missing path doesn't show up as a crash
  - setup() spawns the adapter sidecar after server startup completes
  - RunEvent::Exit cleanup also kills adapter sidecar

* desktop/src/stores/adapterStore.ts: after every successful PUT
  /api/adapters, dynamic-import @tauri-apps/api/core and call
  invoke('restart_adapters_sidecar'). Wrapped in try/catch so non-Tauri
  test environments fall through quietly. Triggers on every config
  change (including pairing code generation, paired-user removal) by
  design — keeps the rule simple and guarantees any save takes effect.

* desktop/src/pages/AdapterSettings.tsx: removed the stale "Server URL"
  text input. The field defaulted to ws://127.0.0.1:3456 but the actual
  server uses a dynamic port chosen at startup. Even when filled in
  correctly, loadConfig() in adapters/common/config.ts gives env var
  priority over file value, so this UI control had zero effect inside
  the desktop app. Standalone-mode adapter users can still edit the
  field directly in adapters.json if they need to.

Bundle size: unchanged at 88 MB .app / 37 MB DMG. The Rust changes
add only a few KB to the desktop main binary.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 00:55:44 +08:00
程序员阿江(Relakkes)
2523ce0cd7 feat(pairing): add pairing management UI to AdapterSettings page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:12:13 +08:00
程序员阿江(Relakkes)
82e6e27687 feat: add IM adapter integration (Telegram + Feishu) with web settings UI
Implement IM adapters allowing users to chat with Claude Code from Telegram
and Feishu/Lark. Includes persistent session management (chatId→sessionId
mapping), project selection via /projects command, and a web UI settings page
for configuring bot tokens, allowed users, and default project directory.

Key changes:
- adapters/: Telegram and Feishu adapter scripts with shared common modules
  (WsBridge, MessageBuffer, SessionStore, HttpClient, config, formatting)
- Backend: adapterService + REST API (GET/PUT /api/adapters) with secret masking
- Frontend: AdapterSettings page in Settings tab with i18n support
- DirectoryPicker: use React Portal for dropdown to fix overflow clipping

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 19:38:51 +08:00