Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>DD Code GUINew to Visual Studio Code? Get it now.
DD Code GUI

DD Code GUI

ddcode-gui

|
1 install
| (0) | Free
AI-powered coding assistant. Dual-engine chat (Claude Agent SDK + Codex SDK), MCP integration, skill system, CLI tools, dark/light themes, i18n (Chinese/English).
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

DD Code GUI — VS Code Extension

AI-powered code assistant for VS Code. Dual-engine (Claude Agent SDK + Codex SDK) chat with tool calls, MCP, terminal.

Features

AI Chat

  • Dual-engine streaming chat — Claude Agent SDK + Codex SDK with tool calls
  • Slash commands — /help, /clear, /new, /compact, /summarize, /context, /mcp, /skills, /plan, /fix, /tests and more
  • @-file mentions — type @ in chat input to search and reference workspace files
  • Multi-agent mode (Codex) — configurable threads, depth, custom agent roles

Code Operations

  • Keyboard shortcuts — Alt+Shift+8 send cursor context, Alt+Shift+9 code edit popup, Escape abort
  • Right-click context menu — "DD Code GUI" submenu: Send Selection, Explain, Fix, Optimize, Add Comments
  • SCM commit message — sparkle button in Source Control generates Conventional Commits from staged diff

Tool Ecosystem

  • MCP server integration — 22 marketplace templates + custom stdio/SSE/HTTP servers
  • Skill system — 17 marketplace templates + auto-discovery from disk
  • CLI tools — auto-detect local tools (npm, mvn, git etc.), live-reload config
  • Built-in terminal — full PTY terminal in chat panel

Theme & Language

  • Dark & Light themes — 42 CSS variable pairs, adaptive UI (scrollbars, code blocks, tool panels, terminal)
  • Internationalization — Chinese/English UI, instant switch

Engine Bridge

  • Moon Bridge — local HTTP proxy for DeepSeek/Anthropic-compatible API via Codex, port auto-increment
  • Flash-First model routing — auto-select flash/pro model based on task complexity

Project Integration

  • Multi-window safety — advisory file locks prevent session corruption across VS Code windows
  • Project-level settings — settings default to Workspace scope when a workspace is open
  • Global settings — API keys and endpoints shared across projects

Quick Start

cd vscode-extension && npx vsce package

vscode:prepublish auto-runs: tsc → copy-bridge → build-webview → VSIX.

Install: VS Code Extensions → ... → Install from VSIX...

Architecture

React SPA (webview/)          ← zero changes, same codebase as IntelliJ
        ↕ postMessage
VS Code Extension (TypeScript) ← replaces Java glue layer
        ↕ stdin/stdout NDJSON
Node.js Daemon (claude-bridge/) ← zero changes

Project Structure

src/
  extension.ts              # activate/deactivate, ~70 webview message cases, 12 commands, context menu
  daemon/
    daemon-manager.ts       # spawn, heartbeat (15s), crash recovery (max 3, recoveryLock)
    ndjson-stream.ts        # NDJSON line reader/writer (readline + JSON.parse)
  webview/
    webview-provider.ts     # WebviewView provider, bridge script, CSP, message buffering
  handlers/
    chat-handler.ts         # Chat streaming, message accumulation (mirrors ChatSendHandler)
    session-manager.ts      # Session persistence (.claude/sessions/), chunked loading, advisory locks
    config-handler.ts       # MCP/Skills/CLI Tools CRUD + disk scanning
    settings-handler.ts     # Claude/Codex/Global settings with debounced config sync, Workspace/Global scope
    attachment-handler.ts   # File attachment + temp file staging
    commit-handler.ts       # Git commit message generation (SCM button, diff collection)
    mcp-handler.ts          # MCP server management
    skill-handler.ts        # Skill management + auto-discovery
    clitool-handler.ts      # CLI Tool management + env-scanner import
    terminal-handler.ts     # Terminal integration (spawn, resize, input)
    context-handler.ts      # Project context extraction
  mcp/
    editor-state-server.ts  # TCP server (port 0) — 4 tools for idea-state-mcp-server.js
  types/
    messages.ts             # All daemon/webview message type definitions
resources/
  bridge/                   # 28 JS files from claude-bridge/ (copied at build)
  webview/                  # Vite-built index.html (IIFE, single-file inlined)
  mcp-marketplace.json      # 22 MCP server templates
  skills-marketplace.json   # 17 skill templates

Configuration

All settings under deepseek-chat.* namespace. Settings default to Workspace scope when a folder is open, falling back to Global. API keys are stored as plaintext in VS Code configuration.

Setting Default Description
claude.provider DEEPSEEK Provider: DEEPSEEK, ANTHROPIC, LM_STUDIO, OLLAMA, LOCAL, CUSTOM
claude.endpoint https://api.deepseek.com Custom API endpoint (empty = provider default)
claude.apiKey "" API key (stored in VS Code config)
claude.model "" Model ID (empty = Auto)
claude.permissionMode default Tool permission: default, acceptEdits, plan, bypassPermissions
claude.thinkingEnabled true Enable extended thinking
claude.multiAgentEnabled false Allow model to spawn sub-agents (Task/Agent). DeepSeek provider does not support sub-agents
claude.thinkingDepth high Thinking depth: low, medium, high, xhigh, max
claude.responseLanguage ENGLISH Response language preference
codex.provider OPENAI Codex provider: OPENAI, CUSTOM
codex.endpoint https://api.openai.com Custom Codex endpoint
codex.apiKey "" API key (stored in VS Code config)
codex.model "" Model ID (empty = Auto)
codex.responseLanguage ENGLISH Response language for Codex
codex.maxThreads 6 Max parallel threads for multi-agent
codex.maxDepth 1 Max agent delegation depth
codex.multiAgentEnabled false Enable multi-agent mode (needs a spawn-capable provider; DeepSeek not supported)
codex.moonBridgePort 38440 Moon Bridge proxy port (auto-increments on conflict)
codex.cliPath "" Custom CLI path for Codex SDK
global.claudeApiKey "" Default Claude API key (shared across projects)
global.claudeEndpoint "" Default Claude endpoint override
global.codexApiKey "" Default Codex API key (shared across projects)
global.codexEndpoint "" Default Codex endpoint override
global.codexCliPath "" Custom Codex CLI path (global default)
global.codexMoonBridgePort 38440 Default Moon Bridge port (global default)

Custom Agent Roles

Codex settings panel supports custom agent roles. Roles persist in workspace state (not settings.json) and sync to the daemon automatically.

Field Required Description
name Yes Short display name
description Yes Role behavior description
model No Override model for this role
reasoningEffort No Reasoning effort: medium or high

Key Design Patterns

Webview Bridge

  • CSP compliance: No inline scripts. Vite vite-plugin-singlefile inlines JS/CSS into single HTML; extension extracts script bodies to external app.js/bridge.js. Both under localResourceRoots.
  • Message buffering: Object.defineProperty(window, 'onMessage', {set}) traps assignment. Messages arriving before React mounts → buffered in _pendingMessages[] → replayed when window.onMessage is set. Prevents ErrorBoundary crash from missing initial data.
  • retainContextWhenHidden: true: Prevents React state loss when user switches tabs away from chat view.

Settings Sync

  • Debounced config listener: subscribeToChanges() debounces onDidChangeConfiguration 300ms. updateClaudeSettings() loops per-key config.update() — each fires event → debounce coalesces into single callback → one sendCommand to daemon.
  • Split-path sync (non-key vs. apiKey): onDidChangeConfiguration callback does NOT await SecretStorage — the callback is not awaited by VS Code, so async work interleaves with webview messages. During the await gap, fetch_models can race ahead of the settings update. Fix: non-key fields (endpoint, model, provider) sent IMMEDIATELY; apiKey resolved from SecretStorage async in background via (async()=>{...})().catch(()=>{}). Masked placeholder '••••••••' from VS Code config is rejected — never overwrites the real key delivered by init.
  • SecretStorage: API keys stored via context.secrets (legacy — migrated to plaintext VS Code config in 1.0.2)
  • sendInitialData ordering: Data sent BEFORE daemon ready. Settings populated in React state before daemon_status: "ready" arrives.
  • Scope: updateClaudeSettings()/updateCodexSettings() default to ConfigurationTarget.Workspace when a workspace is open, Global otherwise.

Session Persistence (Multi-Window Safe)

  • Advisory file locks: acquireLock() uses fs.writeFileSync(path, pid, {flag: 'wx'}) — exclusive-create semantics. PID stamped inside lock file, 30s staleness detection handles orphan locks from crashed processes.
  • Atomic writes: .tmp + fs.renameSync() ensures readers never see partial writes.
  • Merge on save: saveIndex() and saveSession() re-read on-disk state under lock, merge new entries from other windows before writing. Prevents lost updates in multi-window scenarios.
  • Version tracking: sessions.json stores {version, entries} format. Backward-compatible with old plain-array format via Array.isArray() detection.
  • Session revision: Each saveSession() increments revision field — enables conflict detection.

Session Format

Must match Java buildMessagesFromAccumulation() exactly:

  • User: {role:'user', content:<string>, timestamp:<number>}
  • Assistant: {role:'assistant', content:[{type:'thinking',thinking}, {type:'text',text}, {type:'tool_use',id,name,input}], timestamp}
  • Tool results: SEPARATE {role:'user', content:[{type:'tool_result',tool_use_id,content,is_error}]} message — NOT embedded in tool_use blocks. Webview searches for these to populate tool cards.
  • normalizeMessages() in session-manager.ts handles old-format upgrades.

Daemon Lifecycle

  • Init ordering: spawn → send init → start stdout reader. Critical — init must write stdin before reader starts.
  • Deaf-state detection: stdoutReaderAlive flag. stdout reader close → force crash recovery. Prevents silent failure when pipe breaks but process lives.
  • Double reader prevention: Only restartProcess() creates NdjsonReader. Callers must not duplicate — two readline interfaces on same stream compete for lines.
  • Platform-aware cleanup: Windows process.kill() (TerminateProcess), Unix process.kill('SIGKILL').
  • Log ring buffer: Last 500 daemon log lines retained via logBuffer[], exposed via getRecentLogs() for devtools.

Slash Commands

Format: {name, descZh, descEn, local} objects, NOT string[]. ChatInput.tsx:164 calls c.name.slice(1) — if c is string, c.name is undefined → ErrorBoundary crash. buildSlashCommands() in extension.ts mirrors SlashCommandRegistry.java. Defensive normalization in webview main.tsx handles legacy string[].

Editor State MCP

TCP ServerSocket on port 0. 4 tools: get_open_file_paths, get_current_file_info, get_editor_context, get_selection_text. Port injected into daemon init as mcpServers["idea-state"]. sendFullMcpConfig() dual-coordinates — fires from both daemon ready AND server.start().then(), one-shot via mcpConfigSent flag.

Moon Bridge Port Auto-Increment

  • Port probing: probePort() uses net.createServer().listen(port) to check availability before spawning the Go binary.
  • Auto-increment: If the preferred port is busy, probes up to 10 subsequent ports (38440 → 38441 → … → 38449).
  • Port back-sync: When daemon resolves a different port, it emits moon_bridge_status with port. Extension forwards to webview → SET_CODEX_MOON_BRIDGE_PORT updates the UI.
  • TOCTOU accepted: Probe-use window is milliseconds; if another process grabs the port during that window, the Go binary fails to bind and Moon Bridge reports error status. No corruption risk.

Engine Switch (Provider Switch)

  • Full flow: SettingsSidebar.tsx → sendToJava('switch_provider', {messages, responseLanguage}) → extension.ts → compact_request({messages, provider, options:{responseLanguage}}) → daemon
  • 6 requirements: (1) abort before compact resets streaming, (2) chatHandler.resetStreaming() clears loading flag, (3) messages from frontend state (last 50), (4) responseLanguage from old engine so summarization uses correct language, (5) non-key settings sent immediately after compact, (6) apiKey resolved from SecretStorage async in background
  • Frontend banner: COMPACT_DONE reducer checks window.__switchProviderMeta → shows "引擎已切换" with optional warning text when compact fails

Summary Anti-Hallucination Validation

  • validateSummary(summary, conversationText) shared by both codex-sdk and agent-sdk
  • extractKeyTerms(text) extracts up to 30 terms: filenames from paths, CamelCase identifiers (>6 chars), snake_case (3+ segments), Chinese phrases (2-4 chars). No terms found → auto-pass
  • Validation gate: ratio < 0.15 && matchCount < 3 → low_overlap (fatal). 3+ exact keyword matches always pass. model_rejected → returns null (non-fatal, shows "对话太短")
  • Codex summarizeText() MUST filter content blocks to text/thinking/reasoning/output_text types only — without filtering, tool_use blocks become empty strings, flooding the 15000-char window and pushing technical terms out
  • responseLanguage MUST be in compact_request.options — without it, defaults to 'ENGLISH' → Chinese conversations summarized in English → Chinese terms don't match → low_overlap
  • resolveUpstreamEndpoint() (codex-sdk): Provider checks (DEEPSEEK/OPENAI) MUST precede CODEX_BASE_URL check. Prevents stale CODEX_BASE_URL=https://api.openai.com from short-circuiting before provider === 'DEEPSEEK'

Streaming Context Key

deepseek-chat.streaming set true on send_message, false on daemon done/aborted/error. Escape keybinding uses "when": "deepseek-chat.streaming" for conditional abort.

Additional Patterns

  • Crash recovery: recoveryLock prevents concurrent recovery. recoveryInProgress flag keeps loading: true during send_message restart. stream_resumed sent instead of daemon_status: "ready".
  • Send idempotency: lastSentText/lastSentSessionId/lastSentTime tracked. During recovery, matching send within DEDUP_WINDOW_MS=120000 suppressed.
  • aborted accumulator reset: chat-handler.ts resets accumulators on aborted — prevents stale data leaking into next stream.
  • Skill auto-discovery: Scans .claude/skills/, ~/.claude/skills/, ~/.codemoss/skills/ for *.md files at startup.
  • Right-click UX: webviewProvider.ensureVisible() shows view without toggling (VS Code workbench.view.extension.* is a toggle). File tag chips show line numbers only for selections, not whole files. set_chat_input_text no longer sends @file:xxx (redundant with chips).
  • MCP test Windows: cp.spawn doesn't resolve .cmd/.bat on Windows. Bare commands appended .cmd, then wrapped with cmd.exe /c (mirrors mcp-bridge-server.js).
  • /context command: MUST include mcpServers (array of {name, type, disabled}) and skills (array of {name, displayName, enabled, description}) plus pendingSummary from session. Without these, daemon defaults to empty arrays → MCP/Skill counts always 0.
  • atob() safety: Attachments may contain non-base64 data (e.g., raw file content). SDK internally calls atob() which throws InvalidCharacterError. Validate with BASE64_RE = /^[A-Za-z0-9+/]*={0,2}$/ before atob(); fallback to Buffer.from(data, 'utf-8').toString('base64').
  • syncLock compact unblock: daemon.js enqueue inserts a syncLock blocker when compact/summarize is queued — prevents concurrent claude_settings_update / codex_settings_update from overwriting env vars mid-compact. Resolved in channel-manager.js finally block via cmd._syncUnblock(). Without this, compact reads stale or wrong env vars.
  • Codex multi-agent off → single thread: When multiAgentEnabled === false, codex-sdk-service.js forces agents.max_threads: 1 and agents.max_depth: 0. Without this, SDK defaults to multi-agent behavior even when toggle is off.
  • Daemon stderr tee: daemon.js monkey-patches process.stderr.write to also write to <project>/.claude/daemon/daemon.log. Early writes (before init) buffered in memory, flushed when project path is known. Best-effort; errors silently ignored.

Requirements

  • VS Code ^1.85.0
  • Node.js >= 18 for daemon
  • Agent SDK auto-installed to ~/.codemoss/dependencies/

Keyboard Shortcuts

Shortcut Command When
Alt+Shift+8 Send selection / cursor context to chat editorTextFocus
Alt+Shift+9 Code edit operations (Explain/Fix/Optimize/Add Comments) editorTextFocus
Escape Abort current AI generation deepseek-chat.streaming

Right-Click Context Menu

Editor context menu → "DD Code GUI" submenu (when editor is open):

Command When Behavior
Send Selection to DD Code Chat Always Selection → selected text with line numbers. No selection → cursor context (prefix 2500 + <CURSOR> + suffix 1200 chars)
Explain Code with DD Code Selection Pre-fills "解释以下代码" / "Please explain..."
Fix Code with DD Code Selection Pre-fills "修复以下代码中的问题" / "Please fix bugs..."
Optimize Code with DD Code Selection Pre-fills "优化以下代码" / "Please optimize..."
Add Comments with DD Code Selection Pre-fills "为以下代码添加注释" / "Please add comments..."

Explorer context menu → "Send File to DD Code Chat". Prompt language switches based on responseLanguage setting.

Git Commit Message (SCM)

Click the sparkle button in the Source Control titlebar (or run DD Code GUI: Generate Commit Message with AI). The extension:

  1. Runs git diff --cached (falls back to unstaged changes if nothing staged)
  2. Sends the diff to the AI with a Conventional Commits format prompt
  3. Sets the chat input — submit and the AI generates the message, which can be copied to the SCM input box

Debug

  • Output panel: "DD Code GUI" (View → Output, select from dropdown)
  • Daemon logs: [daemon] prefix in Output panel + ring buffer (getRecentLogs)
  • Debug log file: ~/.claude/vscode-debug.log (extension logs only)
  • Daemon log file: <project>/.claude/daemon/daemon.log (daemon stderr tee, includes resolveUpstreamEndpoint, summarizeText, validation diagnostics). Search summarizeText convTextLen= / terms= / summarization for compact debugging.
  • Sessions: ~/.claude/sessions/
  • Permissions: ~/.claude/daemon-permissions.json
  • Dev extension: F5 → Extension Development Host
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft