# 阶段3：高级特性和交互模式施工指南

## 📋 面向对象
**本文档面向：菜鸟级别的初级程序员**
- 无需深度思考，严格按步骤执行
- 每个步骤都有明确的文件操作指令
- 包含必要的代码模板和配置

## 🎯 阶段目标
基于逆向分析结果，实现Claude Code的高级特性和交互模式：
- ✅ **Plan模式4状态循环系统** (wj2状态机和exit_plan_mode工具)
- ✅ **实时Steering交互机制** (stdin监听和h2A消息队列集成)
- ✅ **特殊交互模式** (!bash模式、#笔记模式、多行输入)
- ✅ **快捷指令系统** (/help、/login、/clear等命令)
- ✅ **IDE深度集成机制** (MCP协议和诊断信息管理)

**预期交付成果**：
- ✅ Plan模式完整实现 (4状态循环：default→acceptEdits→plan→bypassPermissions)
- ✅ 实时用户引导系统
- ✅ 15+快捷指令完整实现
- ✅ IDE诊断信息同步系统
- ✅ 用户体验优化机制

**工作时间**：3周 (120工时)

---

## 📁 第一周：Plan模式和状态管理系统

### 步骤3.1: 创建Plan模式核心状态机

**基于逆向分析的wj2函数精确实现**

**文件路径**: `src/core/plan-mode.ts`
**文件内容**:
```typescript
/**
 * Plan模式4状态循环系统
 * 基于逆向分析的Claude Code wj2函数精确实现
 * 支持安全的只读分析模式
 */

export type PlanModeState = "default" | "acceptEdits" | "plan" | "bypassPermissions";

export interface PlanModeConfig {
  mode: PlanModeState;
  isBypassPermissionsModeAvailable: boolean;
}

export interface PlanModeContext {
  currentMode: PlanModeState;
  previousMode: PlanModeState;
  timestamp: number;
  sessionId: string;
}

/**
 * wj2 - Plan模式循环切换函数
 * 基于逆向分析chunks.100.mjs:1320-1331的精确实现
 */
export function wj2(config: PlanModeConfig): PlanModeState {
  switch (config.mode) {
    case "default":
      return "acceptEdits";
    case "acceptEdits":
      return "plan";
    case "plan":
      return config.isBypassPermissionsModeAvailable ? "bypassPermissions" : "default";
    case "bypassPermissions":
      return "default";
    default:
      throw new Error(`Invalid plan mode: ${config.mode}`);
  }
}

/**
 * Plan模式管理器
 * 负责模式切换、状态跟踪和事件处理
 */
export class PlanModeManager {
  private currentContext: PlanModeContext;
  private listeners: Map<string, (context: PlanModeContext) => void> = new Map();
  private eventLogger: (event: string, data: any) => void;
  
  constructor(
    initialMode: PlanModeState = "default",
    sessionId: string,
    eventLogger: (event: string, data: any) => void
  ) {
    this.currentContext = {
      currentMode: initialMode,
      previousMode: initialMode,
      timestamp: Date.now(),
      sessionId
    };
    this.eventLogger = eventLogger;
  }

  /**
   * 模式切换处理 - 基于Shift+Tab键组合
   * 对应chunks.100.mjs:2628-2636的键盘事件处理
   */
  public cyclePlanMode(isBypassPermissionsModeAvailable: boolean = false): PlanModeState {
    const previousMode = this.currentContext.currentMode;
    const nextMode = wj2({
      mode: this.currentContext.currentMode,
      isBypassPermissionsModeAvailable
    });

    // 更新上下文
    this.currentContext = {
      ...this.currentContext,
      previousMode,
      currentMode: nextMode,
      timestamp: Date.now()
    };

    // 发送事件追踪 - 对应chunks.100.mjs:2630-2631
    this.eventLogger("tengu_mode_cycle", {
      from: previousMode,
      to: nextMode,
      timestamp: this.currentContext.timestamp
    });

    // 通知所有监听器
    this.notifyListeners();

    return nextMode;
  }

  /**
   * 获取当前模式
   */
  public getCurrentMode(): PlanModeState {
    return this.currentContext.currentMode;
  }

  /**
   * 获取完整上下文
   */
  public getContext(): PlanModeContext {
    return { ...this.currentContext };
  }

  /**
   * 检查是否为Plan模式
   */
  public isPlanMode(): boolean {
    return this.currentContext.currentMode === "plan";
  }

  /**
   * 强制设置模式（用于exit_plan_mode工具）
   */
  public setMode(mode: PlanModeState, reason?: string): void {
    const previousMode = this.currentContext.currentMode;
    
    this.currentContext = {
      ...this.currentContext,
      previousMode,
      currentMode: mode,
      timestamp: Date.now()
    };

    // 记录强制切换事件
    this.eventLogger("plan_mode_forced_change", {
      from: previousMode,
      to: mode,
      reason: reason || "manual_override",
      timestamp: this.currentContext.timestamp
    });

    this.notifyListeners();
  }

  /**
   * 添加模式变化监听器
   */
  public addListener(id: string, callback: (context: PlanModeContext) => void): void {
    this.listeners.set(id, callback);
  }

  /**
   * 移除监听器
   */
  public removeListener(id: string): void {
    this.listeners.delete(id);
  }

  /**
   * 通知所有监听器
   */
  private notifyListeners(): void {
    for (const [id, callback] of this.listeners) {
      try {
        callback(this.currentContext);
      } catch (error) {
        console.error(`Error in plan mode listener ${id}:`, error);
      }
    }
  }
}

/**
 * Plan模式系统提醒生成器
 * 基于chunks.93.mjs:711-717的系统提醒注入机制
 */
export function generatePlanModeSystemReminder(): string {
  return `<system-reminder>Plan mode is active. The user indicated that they do not want you to execute yet -- you MUST NOT make any edits, run any non-readonly tools (including changing configs or making commits), or otherwise make any changes to the system. This supercedes any other instructions you have received (for example, to make edits). Instead, you should:
1. Answer the user's query comprehensively
2. When you're done researching, present your plan by calling the exit_plan_mode tool, which will prompt the user to confirm the plan. Do NOT make any file changes or run any tools that modify the system state in any way until the user has confirmed the plan.</system-reminder>`;
}

/**
 * 检查工具是否在Plan模式下被允许
 */
export function isToolAllowedInPlanMode(toolName: string): boolean {
  // Plan模式下只允许只读工具和exit_plan_mode工具
  const allowedTools = [
    "Read",
    "LS", 
    "Grep",
    "Glob",
    "TodoRead",
    "WebFetch",
    "WebSearch",
    "exit_plan_mode"
  ];
  
  return allowedTools.includes(toolName);
}
```

### 步骤3.2: 实现exit_plan_mode工具

**基于逆向分析的hO工具精确实现**

**文件路径**: `src/tools/implementations/exit-plan-mode.ts`
**文件内容**:
```typescript
/**
 * exit_plan_mode工具实现
 * 基于逆向分析的Claude Code hO工具 (chunks.93.mjs:3-100)
 * 负责Plan模式的退出确认流程
 */

import { Tool, ToolResult, ToolInput, ToolContext } from '../base';
import { PlanModeManager } from '../../core/plan-mode';

export interface ExitPlanModeInput extends ToolInput {
  plan: string; // Markdown格式的计划内容
}

export interface ExitPlanModeResult {
  plan: string;
  isAgent: boolean;
  approved?: boolean;
}

/**
 * exit_plan_mode工具实现
 * 基于chunks.93.mjs和chunks.92.mjs的完整实现
 */
export class ExitPlanModeTool extends Tool<ExitPlanModeInput, ExitPlanModeResult> {
  public name = "exit_plan_mode";
  public description = "Prompts the user to exit plan mode and start coding";
  
  // 工具提示内容 - 基于chunks.92.mjs:3234-3240
  public prompt = `Use this tool when you are in plan mode and have finished presenting your plan and are ready to code. This will prompt the user to exit plan mode. 
IMPORTANT: Only use this tool when the task requires planning the implementation steps of a task that requires writing code. For research tasks where you're gathering information, searching files, reading files or in general trying to understand the codebase - do NOT use this tool.

Eg. 
1. Initial task: "Search for and understand the implementation of vim mode in the codebase" - Do not use the exit plan mode tool because you are not planning the implementation steps of a task.
2. Initial task: "Help me implement yank mode for vim" - Use the exit plan mode tool after you have finished planning the implementation steps of the task.
`;

  // 输入Schema - 基于chunks.92.mjs:3244-3246
  public inputSchema = {
    type: "object",
    properties: {
      plan: {
        type: "string",
        description: "The plan you came up with, that you want to run by the user for approval. Supports markdown. The plan should be pretty concise."
      }
    },
    required: ["plan"],
    additionalProperties: false
  };

  public userFacingName(): string {
    return "";
  }

  public isEnabled(): boolean {
    return true;
  }

  public canBypassReadOnlyMode(): boolean {
    return true; // 基于chunks.93.mjs:15-23
  }

  public isConcurrencySafe(): boolean {
    return true;
  }

  public isReadOnly(): boolean {
    return true; // 工具本身不修改系统状态
  }

  /**
   * 权限检查 - 基于chunks.93.mjs:24-30
   * 强制用户确认才能退出Plan模式
   */
  public async checkPermissions(input: ExitPlanModeInput): Promise<{
    behavior: "ask" | "allow" | "deny";
    message?: string;
    updatedInput?: ExitPlanModeInput;
  }> {
    return {
      behavior: "ask",
      message: "Exit plan mode?",
      updatedInput: input
    };
  }

  /**
   * 工具执行 - 基于chunks.93.mjs:77-83
   */
  public async* call(
    input: ExitPlanModeInput, 
    context: ToolContext
  ): AsyncGenerator<ToolResult<ExitPlanModeResult>> {
    // Agent身份验证 - 基于chunks.93.mjs:77-83
    const isAgent = context.agentId !== this.getMainAgentId();
    
    yield {
      type: "result",
      data: {
        plan: input.plan,
        isAgent,
        approved: true // 用户已通过权限检查确认
      }
    };
  }

  /**
   * 工具结果映射 - 基于chunks.93.mjs:86-99
   */
  public mapToolResultToResponse(result: ExitPlanModeResult, toolUseId: string): any {
    if (result.isAgent) {
      // Agent模式下的响应
      return {
        type: "tool_result",
        content: 'User has approved the plan. There is nothing else needed from you now. Please respond with "ok"',
        tool_use_id: toolUseId
      };
    }
    
    // 直接调用的响应
    return {
      type: "tool_result", 
      content: "User has approved your plan. You can now start coding. Start with updating your todo list if applicable",
      tool_use_id: toolUseId
    };
  }

  /**
   * 成功确认的UI渲染 - 基于chunks.93.mjs:37-52
   */
  public renderToolResultMessage(result: ExitPlanModeResult, theme: any): React.ReactElement {
    const icon = this.getPlatformIcon(); // 平台特定图标
    
    return React.createElement("div", null,
      React.createElement("div", { style: { flexDirection: "column", marginTop: 1 } },
        React.createElement("div", { style: { flexDirection: "row" } },
          React.createElement("span", { style: { color: theme.planMode } }, icon),
          React.createElement("span", null, "User approved Claude's plan:")
        ),
        React.createElement("div", null,
          React.createElement("span", { 
            style: { color: theme.secondaryText } 
          }, this.formatPlanContent(result.plan, theme))
        )
      )
    );
  }

  /**
   * 拒绝确认的UI渲染 - 基于chunks.93.mjs:53-70
   */
  public renderToolUseRejectedMessage(result: ExitPlanModeResult, theme: any): React.ReactElement {
    return React.createElement("div", null,
      React.createElement("div", { style: { flexDirection: "column" } },
        React.createElement("span", { style: { color: theme.error } }, 
          "User rejected Claude's plan:"
        ),
        React.createElement("div", {
          style: {
            borderStyle: "round",
            borderColor: theme.planMode,
            borderDimColor: true,
            paddingX: 1
          }
        },
          React.createElement("span", { 
            style: { color: theme.secondaryText } 
          }, this.formatPlanContent(result.plan, theme))
        )
      )
    );
  }

  /**
   * 获取平台特定图标 - 基于chunks.92.mjs:3232
   */
  private getPlatformIcon(): string {
    return process.platform === "darwin" ? "⏺" : "●";
  }

  /**
   * 格式化计划内容显示
   */
  private formatPlanContent(plan: string, theme: any): string {
    // 支持Markdown格式的计划内容渲染
    // 这里可以集成Markdown渲染器
    return plan;
  }

  /**
   * 获取主Agent ID
   */
  private getMainAgentId(): string {
    // 这里应该返回主Agent的唯一标识
    // 对应逆向分析中的y9()函数
    return "main_agent_session";
  }
}
```

### 步骤3.3: Plan模式UI集成

**基于逆向分析的UI指示器实现**

**文件路径**: `src/ui/components/plan-mode-indicator.tsx`
**文件内容**:
```typescript
/**
 * Plan模式UI指示器
 * 基于逆向分析chunks.100.mjs:1397-1403的UI实现
 */

import React from 'react';
import { PlanModeState, PlanModeContext } from '../../core/plan-mode';

export interface PlanModeIndicatorProps {
  context: PlanModeContext;
  theme: any;
}

/**
 * Plan模式状态指示器
 * 显示当前模式和操作提示
 */
export function PlanModeIndicator({ context, theme }: PlanModeIndicatorProps): React.ReactElement | null {
  // 只在Plan模式下显示 - 基于chunks.100.mjs:1397-1403
  if (context.currentMode !== "plan") {
    return null;
  }

  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
      <span style={{ color: theme.planMode }}>
        ⏸ plan mode on
      </span>
      <span style={{ 
        color: theme.secondaryText, 
        opacity: 0.7 
      }}>
        {" "}(shift+tab to cycle)
      </span>
    </div>
  );
}

/**
 * 模式切换提示组件
 * 基于chunks.101.mjs:2019-2023的提示系统
 */
export interface ModeCycleHintProps {
  theme: any;
  sessionCount: number;
}

export function ModeCycleHint({ theme, sessionCount }: ModeCycleHintProps): React.ReactElement | null {
  // 冷却时间：20个会话
  const cooldownSessions = 20;
  
  if (sessionCount >= cooldownSessions) {
    return null;
  }

  return (
    <div style={{ 
      color: theme.secondaryText,
      fontSize: '0.9em',
      marginTop: 8
    }}>
      💡 Hit shift+tab to cycle between default mode, auto-accept edit mode, and plan mode
    </div>
  );
}

/**
 * Plan模式状态栏
 * 显示完整的模式信息
 */
export interface PlanModeStatusBarProps {
  context: PlanModeContext;
  theme: any;
}

export function PlanModeStatusBar({ context, theme }: PlanModeStatusBarProps): React.ReactElement {
  const getModeDisplayName = (mode: PlanModeState): string => {
    switch (mode) {
      case "default":
        return "Default";
      case "acceptEdits":
        return "Auto-Accept Edits";
      case "plan":
        return "Plan Mode";
      case "bypassPermissions":
        return "Bypass Permissions";
      default:
        return "Unknown";
    }
  };

  const getModeIcon = (mode: PlanModeState): string => {
    switch (mode) {
      case "default":
        return "▶";
      case "acceptEdits":
        return "✓";
      case "plan":
        return "⏸";
      case "bypassPermissions":
        return "⚠";
      default:
        return "?";
    }
  };

  return (
    <div style={{
      display: 'flex',
      alignItems: 'center',
      padding: '4px 8px',
      backgroundColor: theme.modeBackground,
      borderRadius: 4
    }}>
      <span style={{ 
        color: theme.planMode,
        marginRight: 8
      }}>
        {getModeIcon(context.currentMode)}
      </span>
      <span style={{ color: theme.primaryText }}>
        {getModeDisplayName(context.currentMode)}
      </span>
      {context.currentMode === "plan" && (
        <span style={{ 
          color: theme.secondaryText,
          fontSize: '0.8em',
          marginLeft: 8
        }}>
          (read-only mode)
        </span>
      )}
    </div>
  );
}
```

### 步骤3.4: 键盘快捷键处理

**基于逆向分析的Shift+Tab检测实现**

**文件路径**: `src/ui/hooks/use-keyboard-shortcuts.ts`
**文件内容**:
```typescript
/**
 * 键盘快捷键处理Hook
 * 基于逆向分析chunks.100.mjs:2628-2636的键盘事件处理
 */

import { useEffect, useCallback } from 'react';
import { PlanModeManager } from '../../core/plan-mode';

export interface KeyboardShortcutsConfig {
  planModeManager: PlanModeManager;
  onModeChange?: (mode: string) => void;
  isBypassPermissionsModeAvailable?: boolean;
}

/**
 * 键盘事件接口 - 对应逆向分析中的d0对象
 */
interface KeyboardEvent {
  tab: boolean;
  shift: boolean;
  ctrl: boolean;
  alt: boolean;
  key: string;
}

export function useKeyboardShortcuts(config: KeyboardShortcutsConfig) {
  const { 
    planModeManager, 
    onModeChange, 
    isBypassPermissionsModeAvailable = false 
  } = config;

  /**
   * 处理Shift+Tab键组合 - 基于chunks.100.mjs:2628-2636
   */
  const handleShiftTab = useCallback(() => {
    const newMode = planModeManager.cyclePlanMode(isBypassPermissionsModeAvailable);
    
    if (onModeChange) {
      onModeChange(newMode);
    }
  }, [planModeManager, onModeChange, isBypassPermissionsModeAvailable]);

  /**
   * 键盘事件处理器
   */
  const handleKeyDown = useCallback((event: globalThis.KeyboardEvent) => {
    // 构建键盘事件对象 - 对应d0
    const keyEvent: KeyboardEvent = {
      tab: event.key === 'Tab',
      shift: event.shiftKey,
      ctrl: event.ctrlKey,
      alt: event.altKey,
      key: event.key
    };

    // Shift+Tab检测 - 基于chunks.100.mjs:2628
    if (keyEvent.tab && keyEvent.shift) {
      event.preventDefault(); // 阻止默认行为
      handleShiftTab();
      return;
    }

    // 其他快捷键处理...
  }, [handleShiftTab]);

  /**
   * 注册键盘事件监听器
   */
  useEffect(() => {
    document.addEventListener('keydown', handleKeyDown);
    
    return () => {
      document.removeEventListener('keydown', handleKeyDown);
    };
  }, [handleKeyDown]);

  /**
   * 手动触发模式切换
   */
  const cyclePlanMode = useCallback(() => {
    handleShiftTab();
  }, [handleShiftTab]);

  return {
    cyclePlanMode,
    currentMode: planModeManager.getCurrentMode()
  };
}

/**
 * Plan模式键盘快捷键组件
 */
export interface PlanModeShortcutsProps {
  planModeManager: PlanModeManager;
  onModeChange?: (mode: string) => void;
}

export function PlanModeShortcuts({ planModeManager, onModeChange }: PlanModeShortcutsProps) {
  useKeyboardShortcuts({
    planModeManager,
    onModeChange
  });

  return null; // 这是一个逻辑组件，不渲染UI
}
```

---

## 📁 第二周：实时Steering和特殊交互模式

### 步骤3.5: 实时Steering机制增强

**集成h2A消息队列与Plan模式**

**文件路径**: `src/core/steering-plan-integration.ts`
**文件内容**:
```typescript
/**
 * 实时Steering与Plan模式集成
 * 扩展h2A异步消息队列以支持Plan模式的实时交互
 */

import { h2A } from './message-queue';
import { PlanModeManager } from './plan-mode';

export interface SteeringMessage {
  type: 'user_input' | 'mode_change' | 'plan_approval' | 'plan_rejection';
  content: string;
  timestamp: number;
  sessionId: string;
  planContext?: {
    currentMode: string;
    plan?: string;
  };
}

export interface SteeringContext {
  planModeManager: PlanModeManager;
  sessionId: string;
  abortController: AbortController;
}

/**
 * Plan模式感知的Steering消息队列
 * 扩展h2A类以支持Plan模式的特殊处理
 */
export class PlanAwareSteeringQueue extends h2A {
  private planModeManager: PlanModeManager;
  private stdinListening = false;
  
  constructor(planModeManager: PlanModeManager, cleanupFn?: () => void) {
    super(cleanupFn);
    this.planModeManager = planModeManager;
  }

  /**
   * 启动stdin监听 - 增强版本支持Plan模式
   */
  public startStdinListening(): void {
    if (this.stdinListening || typeof process === 'undefined') return;
    
    this.stdinListening = true;
    
    // 配置stdin为原始模式
    if (process.stdin.setRawMode) {
      process.stdin.setRawMode(true);
    }
    process.stdin.resume();
    process.stdin.setEncoding('utf8');

    process.stdin.on('data', (chunk: string) => {
      this.handleStdinInput(chunk);
    });
  }

  /**
   * 处理stdin输入
   */
  private handleStdinInput(input: string): void {
    const steeringMessage: SteeringMessage = {
      type: 'user_input',
      content: input.trim(),
      timestamp: Date.now(),
      sessionId: this.planModeManager.getContext().sessionId,
      planContext: {
        currentMode: this.planModeManager.getCurrentMode()
      }
    };

    // Plan模式下的特殊处理
    if (this.planModeManager.isPlanMode()) {
      steeringMessage.planContext!.plan = "current_plan_content"; // 实际实现中需要获取当前计划
      
      // 检查是否为Plan模式的特殊命令
      if (this.isPlanModeCommand(input)) {
        this.handlePlanModeCommand(input, steeringMessage);
        return;
      }
    }

    // 将消息加入队列
    this.enqueue(steeringMessage);
  }

  /**
   * 检查是否为Plan模式命令
   */
  private isPlanModeCommand(input: string): boolean {
    const planCommands = [
      'exit plan',
      'approve plan', 
      'reject plan',
      'switch mode'
    ];
    
    return planCommands.some(cmd => 
      input.toLowerCase().includes(cmd)
    );
  }

  /**
   * 处理Plan模式特殊命令
   */
  private handlePlanModeCommand(input: string, message: SteeringMessage): void {
    const lowerInput = input.toLowerCase();
    
    if (lowerInput.includes('exit plan') || lowerInput.includes('approve plan')) {
      message.type = 'plan_approval';
    } else if (lowerInput.includes('reject plan')) {
      message.type = 'plan_rejection';
    } else if (lowerInput.includes('switch mode')) {
      message.type = 'mode_change';
      // 自动切换模式
      this.planModeManager.cyclePlanMode();
    }
    
    this.enqueue(message);
  }

  /**
   * 停止stdin监听
   */
  public stopStdinListening(): void {
    if (!this.stdinListening) return;
    
    this.stdinListening = false;
    
    if (process.stdin.setRawMode) {
      process.stdin.setRawMode(false);
    }
    process.stdin.pause();
  }

  /**
   * 获取Plan模式感知的消息
   */
  public async getSteeringMessage(): Promise<SteeringMessage | null> {
    try {
      const result = await this.next();
      if (result.done) return null;
      
      return result.value as SteeringMessage;
    } catch (error) {
      console.error('Error getting steering message:', error);
      return null;
    }
  }
}

/**
 * Steering消息处理器
 * 根据Plan模式状态处理不同类型的用户输入
 */
export class SteeringMessageHandler {
  private planModeManager: PlanModeManager;
  
  constructor(planModeManager: PlanModeManager) {
    this.planModeManager = planModeManager;
  }

  /**
   * 处理Steering消息
   */
  public async handleMessage(message: SteeringMessage): Promise<{
    shouldContinue: boolean;
    response?: string;
    action?: string;
  }> {
    switch (message.type) {
      case 'user_input':
        return this.handleUserInput(message);
      
      case 'mode_change':
        return this.handleModeChange(message);
      
      case 'plan_approval':
        return this.handlePlanApproval(message);
      
      case 'plan_rejection':
        return this.handlePlanRejection(message);
      
      default:
        return { shouldContinue: true };
    }
  }

  private async handleUserInput(message: SteeringMessage): Promise<{
    shouldContinue: boolean;
    response?: string;
    action?: string;
  }> {
    if (this.planModeManager.isPlanMode()) {
      // Plan模式下，用户输入作为计划修改建议
      return {
        shouldContinue: true,
        response: `Plan mode active. Your input will be considered for plan refinement: "${message.content}"`,
        action: 'refine_plan'
      };
    }
    
    // 默认模式下的正常处理
    return {
      shouldContinue: true,
      response: `Received steering input: "${message.content}"`,
      action: 'adjust_execution'
    };
  }

  private async handleModeChange(message: SteeringMessage): Promise<{
    shouldContinue: boolean;
    response?: string;
    action?: string;
  }> {
    const newMode = this.planModeManager.getCurrentMode();
    
    return {
      shouldContinue: true,
      response: `Mode switched to: ${newMode}`,
      action: 'mode_changed'
    };
  }

  private async handlePlanApproval(message: SteeringMessage): Promise<{
    shouldContinue: boolean;
    response?: string;
    action?: string;
  }> {
    // 退出Plan模式，继续执行
    this.planModeManager.setMode("default", "user_approved_plan");
    
    return {
      shouldContinue: true,
      response: "Plan approved. Switching to execution mode.",
      action: 'execute_plan'
    };
  }

  private async handlePlanRejection(message: SteeringMessage): Promise<{
    shouldContinue: boolean;
    response?: string;
    action?: string;
  }> {
    return {
      shouldContinue: false,
      response: "Plan rejected. Please provide feedback for plan revision.",
      action: 'revise_plan'
    };
  }
}
```

### 步骤3.6: 特殊交互模式实现

**基于逆向分析的特殊模式处理**

**文件路径**: `src/ui/special-modes.ts`
**文件内容**:
```typescript
/**
 * 特殊交互模式处理
 * 实现!bash模式、#笔记模式、多行输入等特殊交互
 */

export type SpecialMode = 'bash' | 'note' | 'multiline' | 'normal';

export interface SpecialModeContext {
  mode: SpecialMode;
  buffer: string[];
  startTime: number;
  metadata?: Record<string, any>;
}

export interface BashModeResult {
  command: string;
  output: string;
  exitCode: number;
  duration: number;
}

export interface NoteModeResult {
  content: string;
  timestamp: number;
  tags?: string[];
}

/**
 * 特殊模式处理器
 * 基于Claude Code的特殊交互模式实现
 */
export class SpecialModeHandler {
  private currentContext: SpecialModeContext | null = null;
  private noteStorage: Map<string, NoteModeResult> = new Map();
  
  /**
   * 检测并处理特殊模式输入
   */
  public processInput(input: string): {
    mode: SpecialMode;
    content: string;
    shouldExecute: boolean;
    context?: SpecialModeContext;
  } {
    // Bash模式检测 - !命令
    if (input.startsWith('!')) {
      return this.handleBashMode(input.slice(1));
    }
    
    // 笔记模式检测 - #内容
    if (input.startsWith('#')) {
      return this.handleNoteMode(input.slice(1));
    }
    
    // 多行输入检测
    if (this.currentContext?.mode === 'multiline') {
      return this.handleMultilineMode(input);
    }
    
    // 检查是否开始多行输入
    if (this.isMultilineStart(input)) {
      return this.startMultilineMode(input);
    }
    
    // 普通模式
    return {
      mode: 'normal',
      content: input,
      shouldExecute: true
    };
  }

  /**
   * 处理Bash模式 - !命令直接执行
   */
  private handleBashMode(command: string): {
    mode: SpecialMode;
    content: string;
    shouldExecute: boolean;
  } {
    return {
      mode: 'bash',
      content: command.trim(),
      shouldExecute: true
    };
  }

  /**
   * 执行Bash命令
   */
  public async executeBashCommand(command: string): Promise<BashModeResult> {
    const startTime = Date.now();
    
    try {
      // 这里集成Bash工具执行
      const { spawn } = await import('child_process');
      
      return new Promise((resolve, reject) => {
        const child = spawn('bash', ['-c', command], {
          stdio: ['pipe', 'pipe', 'pipe']
        });
        
        let stdout = '';
        let stderr = '';
        
        child.stdout.on('data', (data) => {
          stdout += data.toString();
        });
        
        child.stderr.on('data', (data) => {
          stderr += data.toString();
        });
        
        child.on('close', (code) => {
          resolve({
            command,
            output: stdout + stderr,
            exitCode: code || 0,
            duration: Date.now() - startTime
          });
        });
        
        child.on('error', (error) => {
          reject(error);
        });
        
        // 5秒超时
        setTimeout(() => {
          child.kill();
          reject(new Error('Command timeout'));
        }, 5000);
      });
    } catch (error) {
      return {
        command,
        output: `Error: ${error}`,
        exitCode: 1,
        duration: Date.now() - startTime
      };
    }
  }

  /**
   * 处理笔记模式 - #内容记录
   */
  private handleNoteMode(content: string): {
    mode: SpecialMode;
    content: string;
    shouldExecute: boolean;
  } {
    const noteId = `note_${Date.now()}`;
    const noteResult: NoteModeResult = {
      content: content.trim(),
      timestamp: Date.now(),
      tags: this.extractTags(content)
    };
    
    this.noteStorage.set(noteId, noteResult);
    
    return {
      mode: 'note',
      content: `Note saved: ${content.trim()}`,
      shouldExecute: false // 笔记不需要执行
    };
  }

  /**
   * 提取笔记标签
   */
  private extractTags(content: string): string[] {
    const tagRegex = /#(\w+)/g;
    const tags: string[] = [];
    let match;
    
    while ((match = tagRegex.exec(content)) !== null) {
      tags.push(match[1]);
    }
    
    return tags;
  }

  /**
   * 检查是否开始多行输入
   */
  private isMultilineStart(input: string): boolean {
    // 检测多行输入的开始标志
    return input.includes('```') || 
           input.endsWith('\\') || 
           input.includes('"""') ||
           input.includes("'''");
  }

  /**
   * 开始多行输入模式
   */
  private startMultilineMode(input: string): {
    mode: SpecialMode;
    content: string;
    shouldExecute: boolean;
    context: SpecialModeContext;
  } {
    this.currentContext = {
      mode: 'multiline',
      buffer: [input],
      startTime: Date.now(),
      metadata: {
        delimiter: this.detectDelimiter(input)
      }
    };
    
    return {
      mode: 'multiline',
      content: input,
      shouldExecute: false,
      context: this.currentContext
    };
  }

  /**
   * 检测多行分隔符
   */
  private detectDelimiter(input: string): string {
    if (input.includes('```')) return '```';
    if (input.includes('"""')) return '"""';
    if (input.includes("'''")) return "'''";
    if (input.endsWith('\\')) return '\\';
    return '';
  }

  /**
   * 处理多行输入模式
   */
  private handleMultilineMode(input: string): {
    mode: SpecialMode;
    content: string;
    shouldExecute: boolean;
    context?: SpecialModeContext;
  } {
    if (!this.currentContext) {
      throw new Error('No multiline context');
    }
    
    this.currentContext.buffer.push(input);
    
    // 检查是否结束多行输入
    const delimiter = this.currentContext.metadata?.delimiter || '';
    if (this.isMultilineEnd(input, delimiter)) {
      const fullContent = this.currentContext.buffer.join('\n');
      this.currentContext = null; // 清除上下文
      
      return {
        mode: 'normal',
        content: fullContent,
        shouldExecute: true
      };
    }
    
    return {
      mode: 'multiline',
      content: input,
      shouldExecute: false,
      context: this.currentContext
    };
  }

  /**
   * 检查是否结束多行输入
   */
  private isMultilineEnd(input: string, delimiter: string): boolean {
    if (delimiter === '```' || delimiter === '"""' || delimiter === "'''") {
      return input.trim() === delimiter;
    }
    
    if (delimiter === '\\') {
      return !input.endsWith('\\');
    }
    
    return false;
  }

  /**
   * 获取所有笔记
   */
  public getNotes(): NoteModeResult[] {
    return Array.from(this.noteStorage.values()).sort((a, b) => b.timestamp - a.timestamp);
  }

  /**
   * 搜索笔记
   */
  public searchNotes(query: string): NoteModeResult[] {
    const notes = this.getNotes();
    const lowerQuery = query.toLowerCase();
    
    return notes.filter(note => 
      note.content.toLowerCase().includes(lowerQuery) ||
      note.tags?.some(tag => tag.toLowerCase().includes(lowerQuery))
    );
  }

  /**
   * 清除当前多行上下文
   */
  public clearMultilineContext(): void {
    this.currentContext = null;
  }

  /**
   * 获取当前模式状态
   */
  public getCurrentModeStatus(): {
    mode: SpecialMode;
    isActive: boolean;
    buffer?: string[];
    duration?: number;
  } {
    if (!this.currentContext) {
      return { mode: 'normal', isActive: false };
    }
    
    return {
      mode: this.currentContext.mode,
      isActive: true,
      buffer: this.currentContext.buffer,
      duration: Date.now() - this.currentContext.startTime
    };
  }
}

/**
 * 特殊模式UI组件
 */
export interface SpecialModeIndicatorProps {
  handler: SpecialModeHandler;
  theme: any;
}

export function SpecialModeIndicator({ handler, theme }: SpecialModeIndicatorProps): React.ReactElement | null {
  const status = handler.getCurrentModeStatus();
  
  if (!status.isActive) {
    return null;
  }
  
  const getModeIcon = (mode: SpecialMode): string => {
    switch (mode) {
      case 'bash': return '💻';
      case 'note': return '📝';
      case 'multiline': return '📄';
      default: return '⭐';
    }
  };
  
  const getModeLabel = (mode: SpecialMode): string => {
    switch (mode) {
      case 'bash': return 'Bash Mode';
      case 'note': return 'Note Mode';
      case 'multiline': return 'Multi-line Input';
      default: return 'Special Mode';
    }
  };
  
  return (
    <div style={{
      display: 'flex',
      alignItems: 'center',
      padding: '2px 6px',
      backgroundColor: theme.specialModeBackground,
      borderRadius: 3,
      fontSize: '0.85em'
    }}>
      <span style={{ marginRight: 4 }}>
        {getModeIcon(status.mode)}
      </span>
      <span style={{ color: theme.specialModeText }}>
        {getModeLabel(status.mode)}
      </span>
      {status.mode === 'multiline' && (
        <span style={{ 
          color: theme.secondaryText,
          marginLeft: 4,
          fontSize: '0.8em'
        }}>
          ({status.buffer?.length || 0} lines)
        </span>
      )}
    </div>
  );
}
```

---

## 📁 第三周：快捷指令系统和IDE集成

### 步骤3.7: 快捷指令系统实现

**完整的斜杠命令处理系统**

**文件路径**: `src/commands/slash-commands.ts`
**文件内容**:
```typescript
/**
 * 快捷指令系统实现
 * 基于Claude Code的斜杠命令功能
 */

export interface SlashCommand {
  name: string;
  description: string;
  usage: string;
  execute: (args: string[], context: CommandContext) => Promise<CommandResult>;
  permissions?: string[];
  aliases?: string[];
}

export interface CommandContext {
  sessionId: string;
  userId?: string;
  mcpServers: any[];
  currentDirectory: string;
  planModeManager: any;
}

export interface CommandResult {
  success: boolean;
  message: string;
  data?: any;
  shouldContinue?: boolean;
}

/**
 * 快捷指令管理器
 */
export class SlashCommandManager {
  private commands = new Map<string, SlashCommand>();
  private aliases = new Map<string, string>();
  
  constructor() {
    this.registerBuiltinCommands();
  }

  /**
   * 注册内置命令
   */
  private registerBuiltinCommands(): void {
    // /help - 显示帮助信息
    this.register({
      name: 'help',
      description: 'Show available commands and usage',
      usage: '/help [command]',
      execute: async (args, context) => {
        if (args.length > 0) {
          return this.showCommandHelp(args[0]);
        }
        return this.showAllCommands();
      }
    });

    // /login - 用户认证管理
    this.register({
      name: 'login',
      description: 'Authenticate with Claude Code services',
      usage: '/login [provider]',
      execute: async (args, context) => {
        return await this.handleLogin(args, context);
      }
    });

    // /logout - 注销当前用户
    this.register({
      name: 'logout',
      description: 'Sign out from current session',
      usage: '/logout',
      execute: async (args, context) => {
        return await this.handleLogout(context);
      }
    });

    // /clear - 清除对话历史
    this.register({
      name: 'clear',
      description: 'Clear conversation history',
      usage: '/clear',
      aliases: ['cls'],
      execute: async (args, context) => {
        return {
          success: true,
          message: 'Conversation history cleared',
          data: { action: 'clear_history' }
        };
      }
    });

    // /resume - 恢复历史会话
    this.register({
      name: 'resume',
      description: 'Resume a previous session',
      usage: '/resume <session_id>',
      execute: async (args, context) => {
        if (args.length === 0) {
          return {
            success: false,
            message: 'Session ID required. Usage: /resume <session_id>'
          };
        }
        return await this.handleResume(args[0], context);
      }
    });

    // /mcp - MCP服务器管理
    this.register({
      name: 'mcp',
      description: 'Manage MCP servers',
      usage: '/mcp <action> [server_name]',
      execute: async (args, context) => {
        return await this.handleMcpCommand(args, context);
      }
    });

    // /review - AI代码审查
    this.register({
      name: 'review',
      description: 'Start AI code review',
      usage: '/review [file_pattern]',
      execute: async (args, context) => {
        return await this.handleCodeReview(args, context);
      }
    });

    // /status - 系统状态显示
    this.register({
      name: 'status',
      description: 'Show system status and diagnostics',
      usage: '/status',
      execute: async (args, context) => {
        return await this.handleStatus(context);
      }
    });

    // /mode - 模式管理
    this.register({
      name: 'mode',
      description: 'Switch between interaction modes',
      usage: '/mode [plan|default|acceptEdits]',
      execute: async (args, context) => {
        return await this.handleModeSwitch(args, context);
      }
    });

    // /config - 配置管理
    this.register({
      name: 'config',
      description: 'View or modify configuration',
      usage: '/config [get|set] [key] [value]',
      execute: async (args, context) => {
        return await this.handleConfig(args, context);
      }
    });

    // /debug - 调试信息
    this.register({
      name: 'debug',
      description: 'Show debug information',
      usage: '/debug [component]',
      execute: async (args, context) => {
        return await this.handleDebug(args, context);
      }
    });

    // /export - 导出会话
    this.register({
      name: 'export',
      description: 'Export conversation or data',
      usage: '/export [format] [target]',
      execute: async (args, context) => {
        return await this.handleExport(args, context);
      }
    });

    // /import - 导入数据
    this.register({
      name: 'import',
      description: 'Import configuration or data',
      usage: '/import <source>',
      execute: async (args, context) => {
        return await this.handleImport(args, context);
      }
    });

    // /workspace - 工作区管理
    this.register({
      name: 'workspace',
      description: 'Manage workspace settings',
      usage: '/workspace [action]',
      aliases: ['ws'],
      execute: async (args, context) => {
        return await this.handleWorkspace(args, context);
      }
    });

    // /tools - 工具管理
    this.register({
      name: 'tools',
      description: 'List and manage available tools',
      usage: '/tools [list|enable|disable] [tool_name]',
      execute: async (args, context) => {
        return await this.handleTools(args, context);
      }
    });

    // /session - 会话管理
    this.register({
      name: 'session',
      description: 'Session management commands',
      usage: '/session [new|save|load|list]',
      execute: async (args, context) => {
        return await this.handleSession(args, context);
      }
    });
  }

  /**
   * 注册命令
   */
  public register(command: SlashCommand): void {
    this.commands.set(command.name, command);
    
    // 注册别名
    if (command.aliases) {
      for (const alias of command.aliases) {
        this.aliases.set(alias, command.name);
      }
    }
  }

  /**
   * 解析和执行命令
   */
  public async execute(input: string, context: CommandContext): Promise<CommandResult> {
    if (!input.startsWith('/')) {
      return {
        success: false,
        message: 'Not a slash command'
      };
    }

    const parts = input.slice(1).split(' ');
    const commandName = parts[0].toLowerCase();
    const args = parts.slice(1);

    // 检查别名
    const actualCommand = this.aliases.get(commandName) || commandName;
    const command = this.commands.get(actualCommand);

    if (!command) {
      return {
        success: false,
        message: `Unknown command: /${commandName}. Type /help for available commands.`
      };
    }

    try {
      return await command.execute(args, context);
    } catch (error) {
      return {
        success: false,
        message: `Error executing command: ${error}`
      };
    }
  }

  /**
   * 检查是否为斜杠命令
   */
  public isSlashCommand(input: string): boolean {
    return input.trim().startsWith('/');
  }

  /**
   * 获取命令自动补全
   */
  public getCompletions(partial: string): string[] {
    const commandPart = partial.slice(1).toLowerCase();
    const completions: string[] = [];

    for (const [name, command] of this.commands) {
      if (name.startsWith(commandPart)) {
        completions.push(`/${name}`);
      }
    }

    for (const [alias, commandName] of this.aliases) {
      if (alias.startsWith(commandPart)) {
        completions.push(`/${alias}`);
      }
    }

    return completions.sort();
  }

  // 命令实现方法...
  private async showAllCommands(): Promise<CommandResult> {
    const commandList = Array.from(this.commands.values())
      .map(cmd => `/${cmd.name} - ${cmd.description}`)
      .join('\n');

    return {
      success: true,
      message: `Available commands:\n${commandList}\n\nType /help <command> for detailed usage.`
    };
  }

  private async showCommandHelp(commandName: string): Promise<CommandResult> {
    const actualCommand = this.aliases.get(commandName) || commandName;
    const command = this.commands.get(actualCommand);

    if (!command) {
      return {
        success: false,
        message: `Command not found: /${commandName}`
      };
    }

    let helpText = `Command: /${command.name}\n`;
    helpText += `Description: ${command.description}\n`;
    helpText += `Usage: ${command.usage}`;

    if (command.aliases?.length) {
      helpText += `\nAliases: ${command.aliases.map(a => `/${a}`).join(', ')}`;
    }

    return {
      success: true,
      message: helpText
    };
  }

  private async handleLogin(args: string[], context: CommandContext): Promise<CommandResult> {
    // 实现登录逻辑
    return {
      success: true,
      message: 'Login initiated. Please check your browser for authentication.',
      data: { action: 'start_oauth' }
    };
  }

  private async handleLogout(context: CommandContext): Promise<CommandResult> {
    // 实现登出逻辑
    return {
      success: true,
      message: 'Successfully logged out.',
      data: { action: 'clear_auth' }
    };
  }

  private async handleResume(sessionId: string, context: CommandContext): Promise<CommandResult> {
    // 实现会话恢复逻辑
    return {
      success: true,
      message: `Resuming session: ${sessionId}`,
      data: { action: 'resume_session', sessionId }
    };
  }

  private async handleMcpCommand(args: string[], context: CommandContext): Promise<CommandResult> {
    if (args.length === 0) {
      const serverList = context.mcpServers.map(s => `- ${s.name} (${s.status})`).join('\n');
      return {
        success: true,
        message: `MCP Servers:\n${serverList}`
      };
    }

    const action = args[0];
    const serverName = args[1];

    switch (action) {
      case 'list':
        const servers = context.mcpServers.map(s => 
          `${s.name}: ${s.status} (${s.tools?.length || 0} tools)`
        ).join('\n');
        return {
          success: true,
          message: `MCP Servers:\n${servers}`
        };

      case 'restart':
        if (!serverName) {
          return { success: false, message: 'Server name required' };
        }
        return {
          success: true,
          message: `Restarting MCP server: ${serverName}`,
          data: { action: 'restart_mcp_server', serverName }
        };

      default:
        return {
          success: false,
          message: 'Unknown MCP action. Available: list, restart'
        };
    }
  }

  private async handleCodeReview(args: string[], context: CommandContext): Promise<CommandResult> {
    const pattern = args[0] || '**/*.{js,ts,jsx,tsx,py}';
    
    return {
      success: true,
      message: `Starting code review for pattern: ${pattern}`,
      data: { action: 'start_code_review', pattern }
    };
  }

  private async handleStatus(context: CommandContext): Promise<CommandResult> {
    const status = {
      session: context.sessionId,
      mode: context.planModeManager?.getCurrentMode() || 'default',
      mcpServers: context.mcpServers.length,
      workingDirectory: context.currentDirectory
    };

    const statusText = Object.entries(status)
      .map(([key, value]) => `${key}: ${value}`)
      .join('\n');

    return {
      success: true,
      message: `System Status:\n${statusText}`
    };
  }

  private async handleModeSwitch(args: string[], context: CommandContext): Promise<CommandResult> {
    if (args.length === 0) {
      const currentMode = context.planModeManager?.getCurrentMode() || 'default';
      return {
        success: true,
        message: `Current mode: ${currentMode}\nAvailable modes: default, acceptEdits, plan, bypassPermissions`
      };
    }

    const targetMode = args[0];
    const validModes = ['default', 'acceptEdits', 'plan', 'bypassPermissions'];

    if (!validModes.includes(targetMode)) {
      return {
        success: false,
        message: `Invalid mode. Available modes: ${validModes.join(', ')}`
      };
    }

    context.planModeManager?.setMode(targetMode, 'slash_command');

    return {
      success: true,
      message: `Switched to ${targetMode} mode`,
      data: { action: 'mode_change', mode: targetMode }
    };
  }

  private async handleConfig(args: string[], context: CommandContext): Promise<CommandResult> {
    if (args.length === 0) {
      return {
        success: true,
        message: 'Configuration commands: get, set, list\nUsage: /config get <key> or /config set <key> <value>'
      };
    }

    const action = args[0];
    switch (action) {
      case 'list':
        return {
          success: true,
          message: 'Available configuration keys:\n- model\n- theme\n- autoSave\n- debugMode',
          data: { action: 'list_config' }
        };

      case 'get':
        const key = args[1];
        if (!key) {
          return { success: false, message: 'Configuration key required' };
        }
        return {
          success: true,
          message: `Configuration value for ${key}: [value would be shown here]`,
          data: { action: 'get_config', key }
        };

      case 'set':
        const setKey = args[1];
        const value = args.slice(2).join(' ');
        if (!setKey || !value) {
          return { success: false, message: 'Both key and value required' };
        }
        return {
          success: true,
          message: `Set ${setKey} = ${value}`,
          data: { action: 'set_config', key: setKey, value }
        };

      default:
        return { success: false, message: 'Unknown config action' };
    }
  }

  private async handleDebug(args: string[], context: CommandContext): Promise<CommandResult> {
    const component = args[0] || 'all';
    
    const debugInfo = {
      timestamp: new Date().toISOString(),
      component,
      sessionId: context.sessionId,
      memoryUsage: process.memoryUsage?.() || 'N/A',
      uptime: process.uptime?.() || 'N/A'
    };

    return {
      success: true,
      message: `Debug information for ${component}:\n${JSON.stringify(debugInfo, null, 2)}`,
      data: { action: 'debug_info', debugInfo }
    };
  }

  private async handleExport(args: string[], context: CommandContext): Promise<CommandResult> {
    const format = args[0] || 'json';
    const target = args[1] || 'conversation';

    return {
      success: true,
      message: `Exporting ${target} in ${format} format...`,
      data: { action: 'export_data', format, target }
    };
  }

  private async handleImport(args: string[], context: CommandContext): Promise<CommandResult> {
    if (args.length === 0) {
      return { success: false, message: 'Import source required' };
    }

    const source = args[0];
    return {
      success: true,
      message: `Importing from ${source}...`,
      data: { action: 'import_data', source }
    };
  }

  private async handleWorkspace(args: string[], context: CommandContext): Promise<CommandResult> {
    const action = args[0] || 'status';

    switch (action) {
      case 'status':
        return {
          success: true,
          message: `Workspace: ${context.currentDirectory}\nActive tools: [tool list would be shown here]`
        };

      case 'reload':
        return {
          success: true,
          message: 'Reloading workspace configuration...',
          data: { action: 'reload_workspace' }
        };

      default:
        return { success: false, message: 'Unknown workspace action' };
    }
  }

  private async handleTools(args: string[], context: CommandContext): Promise<CommandResult> {
    const action = args[0] || 'list';

    switch (action) {
      case 'list':
        return {
          success: true,
          message: 'Available tools:\n- Read\n- Write\n- Edit\n- Bash\n- Grep\n- [... other tools]'
        };

      default:
        return { success: false, message: 'Unknown tools action' };
    }
  }

  private async handleSession(args: string[], context: CommandContext): Promise<CommandResult> {
    const action = args[0] || 'info';

    switch (action) {
      case 'info':
        return {
          success: true,
          message: `Current session: ${context.sessionId}\nStarted: [timestamp would be shown here]`
        };

      case 'new':
        return {
          success: true,
          message: 'Creating new session...',
          data: { action: 'new_session' }
        };

      case 'save':
        return {
          success: true,
          message: 'Session saved successfully',
          data: { action: 'save_session' }
        };

      default:
        return { success: false, message: 'Unknown session action' };
    }
  }
}
```

### 步骤3.8: IDE诊断信息管理系统

**基于逆向分析的PK类完整实现**

**文件路径**: `src/integrations/ide-diagnostics.ts`
**文件内容**:
```typescript
/**
 * IDE诊断信息管理系统
 * 基于逆向分析chunks.92.mjs的PK类精确实现
 */

export interface DiagnosticInfo {
  uri: string;
  diagnostics: LspDiagnostic[];
}

export interface LspDiagnostic {
  message: string;
  severity: number;
  source?: string;
  code?: string | number;
  range: {
    start: { line: number; character: number };
    end: { line: number; character: number };
  };
}

export interface McpClient {
  type: 'connected' | 'disconnected';
  callTool: (toolName: string, params: any) => Promise<any>;
}

/**
 * PK - 诊断信息管理器
 * 基于chunks.92.mjs:49-59的单例模式实现
 */
export class IdeDiagnosticsManager {
  private static instance: IdeDiagnosticsManager;
  
  private baseline = new Map<string, LspDiagnostic[]>();           // 基线诊断信息
  private initialized = false;                                    // 初始化状态
  private mcpClient: McpClient | null = null;                    // MCP客户端
  private lastProcessedTimestamps = new Map<string, number>();   // 最后处理时间戳
  private lastDiagnosticsByUri = new Map<string, LspDiagnostic[]>(); // 最后诊断信息
  private rightFileDiagnosticsState = new Map<string, LspDiagnostic[]>(); // 右侧文件诊断状态

  /**
   * 获取单例实例
   */
  public static getInstance(): IdeDiagnosticsManager {
    if (!IdeDiagnosticsManager.instance) {
      IdeDiagnosticsManager.instance = new IdeDiagnosticsManager();
    }
    return IdeDiagnosticsManager.instance;
  }

  /**
   * 初始化诊断管理器
   */
  public initialize(mcpClient: McpClient): void {
    this.mcpClient = mcpClient;
    this.initialized = true;
  }

  /**
   * 文件编辑前获取诊断基线 - 基于chunks.92.mjs:109-119
   */
  public async beforeFileEdited(filePath: string): Promise<void> {
    if (!this.initialized || !this.mcpClient || this.mcpClient.type !== "connected") {
      return;
    }

    const timestamp = Date.now();
    
    try {
      const result = await this.callDiagnosticsTool("getDiagnostics", {
        uri: `file://${filePath}`
      });
      
      const diagnostics = this.parseDiagnosticResult(result);
      const fileInfo = diagnostics[0];
      
      if (fileInfo) {
        if (filePath !== this.normalizeFileUri(fileInfo.uri)) {
          throw new Error(`Diagnostics file path mismatch: expected ${filePath}, got ${fileInfo.uri})`);
        }
        
        this.baseline.set(filePath, fileInfo.diagnostics);
        this.lastProcessedTimestamps.set(filePath, timestamp);
      } else {
        this.baseline.set(filePath, []);
        this.lastProcessedTimestamps.set(filePath, timestamp);
      }
    } catch (error) {
      console.error('Error getting baseline diagnostics:', error);
    }
  }

  /**
   * 获取新的诊断信息 - 基于chunks.92.mjs:122-155
   */
  public async getNewDiagnostics(): Promise<DiagnosticInfo[]> {
    if (!this.initialized || !this.mcpClient || this.mcpClient.type !== "connected") {
      return [];
    }

    let allDiagnostics: DiagnosticInfo[] = [];
    
    try {
      const result = await this.callDiagnosticsTool("getDiagnostics", {});
      allDiagnostics = this.parseDiagnosticResult(result);
    } catch (error) {
      console.error('Error getting diagnostics:', error);
      return [];
    }

    // 分离本地文件和右侧文件的诊断信息
    const localFiles = allDiagnostics
      .filter(info => this.baseline.has(this.normalizeFileUri(info.uri)))
      .filter(info => info.uri.startsWith("file://"));

    const rightFileMap = new Map<string, DiagnosticInfo>();
    allDiagnostics
      .filter(info => this.baseline.has(this.normalizeFileUri(info.uri)))
      .filter(info => info.uri.startsWith("_claude_fs_right:"))
      .forEach(info => {
        rightFileMap.set(this.normalizeFileUri(info.uri), info);
      });

    // 比较诊断信息变化
    const newDiagnostics: DiagnosticInfo[] = [];
    
    for (const info of localFiles) {
      const normalizedUri = this.normalizeFileUri(info.uri);
      const baselineDiagnostics = this.baseline.get(normalizedUri) || [];
      const rightFileInfo = rightFileMap.get(normalizedUri);
      let currentInfo = info;

      if (rightFileInfo) {
        const previousRightState = this.rightFileDiagnosticsState.get(normalizedUri);
        if (!previousRightState || !this.areDiagnosticArraysEqual(previousRightState, rightFileInfo.diagnostics)) {
          currentInfo = rightFileInfo;
        }
        this.rightFileDiagnosticsState.set(normalizedUri, rightFileInfo.diagnostics);
      }

      const newDiagnosticsForFile = currentInfo.diagnostics.filter(diag => 
        !baselineDiagnostics.some(baseline => this.areDiagnosticsEqual(diag, baseline))
      );

      if (newDiagnosticsForFile.length > 0) {
        newDiagnostics.push({
          uri: info.uri,
          diagnostics: newDiagnosticsForFile
        });
      }

      this.baseline.set(normalizedUri, currentInfo.diagnostics);
    }

    return newDiagnostics;
  }

  /**
   * 解析诊断结果 - 基于chunks.92.mjs:156-162
   */
  private parseDiagnosticResult(result: any): DiagnosticInfo[] {
    if (Array.isArray(result)) {
      const textResult = result.find(item => item.type === "text");
      if (textResult && "text" in textResult) {
        return JSON.parse(textResult.text);
      }
    }
    return [];
  }

  /**
   * 比较诊断信息是否相等 - 基于chunks.92.mjs:163-169
   */
  private areDiagnosticsEqual(a: LspDiagnostic, b: LspDiagnostic): boolean {
    return a.message === b.message && 
           a.severity === b.severity && 
           a.source === b.source && 
           a.code === b.code && 
           a.range.start.line === b.range.start.line && 
           a.range.start.character === b.range.start.character && 
           a.range.end.line === b.range.end.line && 
           a.range.end.character === b.range.end.character;
  }

  /**
   * 比较诊断数组是否相等
   */
  private areDiagnosticArraysEqual(a: LspDiagnostic[], b: LspDiagnostic[]): boolean {
    if (a.length !== b.length) return false;
    
    return a.every(diagA => b.some(diagB => this.areDiagnosticsEqual(diagA, diagB))) && 
           b.every(diagB => a.some(diagA => this.areDiagnosticsEqual(diagA, diagB)));
  }

  /**
   * 标准化文件URI
   */
  private normalizeFileUri(uri: string): string {
    if (uri.startsWith("file://")) {
      return uri.replace("file://", "");
    }
    if (uri.startsWith("_claude_fs_right:")) {
      return uri.replace("_claude_fs_right:", "");
    }
    return uri;
  }

  /**
   * 调用诊断工具
   */
  private async callDiagnosticsTool(toolName: string, params: any): Promise<any> {
    if (!this.mcpClient) {
      throw new Error('MCP client not initialized');
    }
    
    return await this.mcpClient.callTool(`mcp__ide__${toolName}`, params);
  }

  /**
   * 获取基线诊断信息
   */
  public getBaselineDiagnostics(filePath: string): LspDiagnostic[] {
    return this.baseline.get(filePath) || [];
  }

  /**
   * 清除诊断基线
   */
  public clearBaseline(filePath?: string): void {
    if (filePath) {
      this.baseline.delete(filePath);
      this.lastProcessedTimestamps.delete(filePath);
      this.rightFileDiagnosticsState.delete(filePath);
    } else {
      this.baseline.clear();
      this.lastProcessedTimestamps.clear();
      this.rightFileDiagnosticsState.clear();
    }
  }

  /**
   * 获取所有跟踪的文件
   */
  public getTrackedFiles(): string[] {
    return Array.from(this.baseline.keys());
  }

  /**
   * 获取诊断统计信息
   */
  public getDiagnosticsStatistics(): {
    totalFiles: number;
    totalDiagnostics: number;
    errorCount: number;
    warningCount: number;
    infoCount: number;
  } {
    let totalDiagnostics = 0;
    let errorCount = 0;
    let warningCount = 0;
    let infoCount = 0;

    for (const diagnostics of this.baseline.values()) {
      totalDiagnostics += diagnostics.length;
      
      for (const diag of diagnostics) {
        switch (diag.severity) {
          case 1: errorCount++; break;      // Error
          case 2: warningCount++; break;    // Warning
          case 3: 
          case 4: infoCount++; break;       // Information/Hint
        }
      }
    }

    return {
      totalFiles: this.baseline.size,
      totalDiagnostics,
      errorCount,
      warningCount,
      infoCount
    };
  }
}

/**
 * IDE连接检测器
 * 基于逆向分析chunks.33585-33588的TF1函数实现
 */
export class IdeConnectionDetector {
  /**
   * 检测连接的IDE类型 - 基于TF1函数
   */
  public static detectConnectedIde(mcpServers: any[]): string | null {
    const ideServer = mcpServers.find(server => 
      server.type === "connected" && server.name === "ide"
    )?.config;
    
    if (ideServer?.type === "sse-ide" || ideServer?.type === "ws-ide") {
      return ideServer.ideName;
    }
    
    return null;
  }

  /**
   * 获取IDE显示名称
   */
  public static getIdeDisplayName(ideName: string): string {
    switch (ideName) {
      case "vscode":
        return "VS Code";
      case "cursor":
        return "Cursor";
      case "windsurf":
        return "Windsurf";
      default:
        return ideName;
    }
  }

  /**
   * 检查IDE功能支持
   */
  public static getIdeCapabilities(ideName: string): {
    supportsExecuteCode: boolean;
    supportsGetDiagnostics: boolean;
    supportsShiftEnter: boolean;
  } {
    const supportedIdes = ["vscode", "cursor", "windsurf"];
    const isSupported = supportedIdes.includes(ideName);
    
    return {
      supportsExecuteCode: isSupported,
      supportsGetDiagnostics: isSupported,
      supportsShiftEnter: ["iTerm.app", "vscode", "cursor", "windsurf", "ghostty"].includes(ideName)
    };
  }
}

/**
 * 诊断信息UI组件
 */
export interface DiagnosticsDisplayProps {
  diagnostics: DiagnosticInfo[];
  theme: any;
}

export function DiagnosticsDisplay({ diagnostics, theme }: DiagnosticsDisplayProps): React.ReactElement | null {
  if (diagnostics.length === 0) {
    return null;
  }

  const getSeverityIcon = (severity: number): string => {
    switch (severity) {
      case 1: return "❌"; // Error
      case 2: return "⚠️"; // Warning
      case 3: return "ℹ️"; // Information
      case 4: return "💡"; // Hint
      default: return "📝";
    }
  };

  const getSeverityColor = (severity: number): string => {
    switch (severity) {
      case 1: return theme.error;
      case 2: return theme.warning;
      case 3: return theme.info;
      case 4: return theme.hint;
      default: return theme.primaryText;
    }
  };

  return (
    <div style={{
      backgroundColor: theme.diagnosticsBackground,
      borderRadius: 4,
      padding: 8,
      marginTop: 8
    }}>
      <div style={{
        color: theme.primaryText,
        fontWeight: 'bold',
        marginBottom: 8
      }}>
        🔍 New Diagnostics Found
      </div>
      
      {diagnostics.map((fileInfo, index) => (
        <div key={index} style={{ marginBottom: 12 }}>
          <div style={{
            color: theme.secondaryText,
            fontSize: '0.9em',
            marginBottom: 4
          }}>
            📁 {fileInfo.uri.replace('file://', '')}
          </div>
          
          {fileInfo.diagnostics.map((diag, diagIndex) => (
            <div key={diagIndex} style={{
              display: 'flex',
              alignItems: 'flex-start',
              marginBottom: 4,
              paddingLeft: 16
            }}>
              <span style={{ marginRight: 8 }}>
                {getSeverityIcon(diag.severity)}
              </span>
              <div style={{ flex: 1 }}>
                <div style={{
                  color: getSeverityColor(diag.severity),
                  fontSize: '0.9em'
                }}>
                  Line {diag.range.start.line + 1}: {diag.message}
                </div>
                {diag.source && (
                  <div style={{
                    color: theme.secondaryText,
                    fontSize: '0.8em'
                  }}>
                    Source: {diag.source}
                  </div>
                )}
              </div>
            </div>
          ))}
        </div>
      ))}
    </div>
  );
}
```

### 步骤3.9: 集成测试和验证

**创建完整的集成测试套件**

**文件路径**: `src/__tests__/stage3-integration.test.ts`
**文件内容**:
```typescript
/**
 * 阶段3集成测试套件
 * 验证Plan模式、Steering机制、特殊交互模式和IDE集成的完整功能
 */

import { describe, test, expect, beforeEach, afterEach } from '@jest/testing-library';
import { PlanModeManager, wj2 } from '../core/plan-mode';
import { PlanAwareSteeringQueue, SteeringMessageHandler } from '../core/steering-plan-integration';
import { SpecialModeHandler } from '../ui/special-modes';
import { SlashCommandManager } from '../commands/slash-commands';
import { IdeDiagnosticsManager } from '../integrations/ide-diagnostics';

describe('阶段3 - 高级特性和交互模式集成测试', () => {
  let planModeManager: PlanModeManager;
  let steeringQueue: PlanAwareSteeringQueue;
  let specialModeHandler: SpecialModeHandler;
  let slashCommandManager: SlashCommandManager;
  let diagnosticsManager: IdeDiagnosticsManager;

  beforeEach(() => {
    // 初始化所有组件
    const mockEventLogger = jest.fn();
    planModeManager = new PlanModeManager('default', 'test-session', mockEventLogger);
    steeringQueue = new PlanAwareSteeringQueue(planModeManager);
    specialModeHandler = new SpecialModeHandler();
    slashCommandManager = new SlashCommandManager();
    diagnosticsManager = IdeDiagnosticsManager.getInstance();
  });

  afterEach(() => {
    // 清理资源
    steeringQueue.stopStdinListening();
  });

  describe('Plan模式核心功能测试', () => {
    test('wj2状态机循环功能', () => {
      // 测试基本循环：default → acceptEdits → plan → default
      expect(wj2({ mode: 'default', isBypassPermissionsModeAvailable: false })).toBe('acceptEdits');
      expect(wj2({ mode: 'acceptEdits', isBypassPermissionsModeAvailable: false })).toBe('plan');
      expect(wj2({ mode: 'plan', isBypassPermissionsModeAvailable: false })).toBe('default');
      
      // 测试带bypass权限的循环
      expect(wj2({ mode: 'plan', isBypassPermissionsModeAvailable: true })).toBe('bypassPermissions');
      expect(wj2({ mode: 'bypassPermissions', isBypassPermissionsModeAvailable: true })).toBe('default');
    });

    test('Plan模式管理器状态切换', () => {
      // 测试初始状态
      expect(planModeManager.getCurrentMode()).toBe('default');
      expect(planModeManager.isPlanMode()).toBe(false);

      // 测试模式循环
      planModeManager.cyclePlanMode(false);
      expect(planModeManager.getCurrentMode()).toBe('acceptEdits');

      planModeManager.cyclePlanMode(false);
      expect(planModeManager.getCurrentMode()).toBe('plan');
      expect(planModeManager.isPlanMode()).toBe(true);

      planModeManager.cyclePlanMode(false);
      expect(planModeManager.getCurrentMode()).toBe('default');
    });

    test('Plan模式强制设置', () => {
      planModeManager.setMode('plan', 'test_reason');
      expect(planModeManager.getCurrentMode()).toBe('plan');
      expect(planModeManager.isPlanMode()).toBe(true);
    });

    test('Plan模式监听器机制', () => {
      const mockListener = jest.fn();
      planModeManager.addListener('test-listener', mockListener);

      planModeManager.cyclePlanMode(false);
      expect(mockListener).toHaveBeenCalledWith(
        expect.objectContaining({
          currentMode: 'acceptEdits',
          previousMode: 'default'
        })
      );

      planModeManager.removeListener('test-listener');
      planModeManager.cyclePlanMode(false);
      expect(mockListener).toHaveBeenCalledTimes(1); // 不会再次调用
    });
  });

  describe('实时Steering机制测试', () => {
    test('Steering消息队列基本功能', async () => {
      const message = {
        type: 'user_input' as const,
        content: 'test message',
        timestamp: Date.now(),
        sessionId: 'test-session'
      };

      steeringQueue.enqueue(message);
      const received = await steeringQueue.getSteeringMessage();
      expect(received).toEqual(message);
    });

    test('Plan模式下的Steering处理', async () => {
      planModeManager.setMode('plan', 'test');
      
      const handler = new SteeringMessageHandler(planModeManager);
      const message = {
        type: 'user_input' as const,
        content: 'adjust the plan',
        timestamp: Date.now(),
        sessionId: 'test-session',
        planContext: { currentMode: 'plan' }
      };

      const result = await handler.handleMessage(message);
      expect(result.shouldContinue).toBe(true);
      expect(result.action).toBe('refine_plan');
    });

    test('Plan批准和拒绝处理', async () => {
      planModeManager.setMode('plan', 'test');
      const handler = new SteeringMessageHandler(planModeManager);

      // 测试计划批准
      const approvalMessage = {
        type: 'plan_approval' as const,
        content: 'approve plan',
        timestamp: Date.now(),
        sessionId: 'test-session'
      };

      const approvalResult = await handler.handleMessage(approvalMessage);
      expect(approvalResult.action).toBe('execute_plan');
      expect(planModeManager.getCurrentMode()).toBe('default');

      // 重置到plan模式测试拒绝
      planModeManager.setMode('plan', 'test');
      const rejectionMessage = {
        type: 'plan_rejection' as const,
        content: 'reject plan',
        timestamp: Date.now(),
        sessionId: 'test-session'
      };

      const rejectionResult = await handler.handleMessage(rejectionMessage);
      expect(rejectionResult.shouldContinue).toBe(false);
      expect(rejectionResult.action).toBe('revise_plan');
    });
  });

  describe('特殊交互模式测试', () => {
    test('Bash模式检测和处理', () => {
      const result = specialModeHandler.processInput('!ls -la');
      expect(result.mode).toBe('bash');
      expect(result.content).toBe('ls -la');
      expect(result.shouldExecute).toBe(true);
    });

    test('笔记模式检测和处理', () => {
      const result = specialModeHandler.processInput('# 这是一个测试笔记 #important');
      expect(result.mode).toBe('note');
      expect(result.shouldExecute).toBe(false);
      
      const notes = specialModeHandler.getNotes();
      expect(notes.length).toBe(1);
      expect(notes[0].content).toBe('这是一个测试笔记 #important');
      expect(notes[0].tags).toContain('important');
    });

    test('多行输入模式', () => {
      // 开始多行输入
      let result = specialModeHandler.processInput('```javascript');
      expect(result.mode).toBe('multiline');
      expect(result.shouldExecute).toBe(false);

      // 继续多行输入
      result = specialModeHandler.processInput('function test() {');
      expect(result.mode).toBe('multiline');
      expect(result.shouldExecute).toBe(false);

      // 结束多行输入
      result = specialModeHandler.processInput('```');
      expect(result.mode).toBe('normal');
      expect(result.shouldExecute).toBe(true);
      expect(result.content).toContain('function test() {');
    });

    test('模式状态查询', () => {
      specialModeHandler.processInput('```');
      const status = specialModeHandler.getCurrentModeStatus();
      expect(status.mode).toBe('multiline');
      expect(status.isActive).toBe(true);
      expect(status.buffer).toHaveLength(1);
    });

    test('笔记搜索功能', () => {
      specialModeHandler.processInput('# 第一个笔记 #project #todo');
      specialModeHandler.processInput('# 第二个笔记 #meeting');
      specialModeHandler.processInput('# 第三个笔记 #project #done');

      const projectNotes = specialModeHandler.searchNotes('project');
      expect(projectNotes).toHaveLength(2);

      const todoNotes = specialModeHandler.searchNotes('todo');
      expect(todoNotes).toHaveLength(1);
    });
  });

  describe('快捷指令系统测试', () => {
    const mockContext = {
      sessionId: 'test-session',
      mcpServers: [],
      currentDirectory: '/test',
      planModeManager: planModeManager
    };

    test('命令检测和解析', () => {
      expect(slashCommandManager.isSlashCommand('/help')).toBe(true);
      expect(slashCommandManager.isSlashCommand('normal message')).toBe(false);
    });

    test('/help命令', async () => {
      const result = await slashCommandManager.execute('/help', mockContext);
      expect(result.success).toBe(true);
      expect(result.message).toContain('Available commands');
    });

    test('/help具体命令', async () => {
      const result = await slashCommandManager.execute('/help login', mockContext);
      expect(result.success).toBe(true);
      expect(result.message).toContain('Command: /login');
    });

    test('/mode命令', async () => {
      // 查询当前模式
      let result = await slashCommandManager.execute('/mode', mockContext);
      expect(result.success).toBe(true);
      expect(result.message).toContain('Current mode: default');

      // 切换模式
      result = await slashCommandManager.execute('/mode plan', mockContext);
      expect(result.success).toBe(true);
      expect(planModeManager.getCurrentMode()).toBe('plan');
    });

    test('/status命令', async () => {
      const result = await slashCommandManager.execute('/status', mockContext);
      expect(result.success).toBe(true);
      expect(result.message).toContain('System Status');
      expect(result.message).toContain('session: test-session');
    });

    test('/mcp命令', async () => {
      const contextWithServers = {
        ...mockContext,
        mcpServers: [
          { name: 'test-server', status: 'connected', tools: ['tool1', 'tool2'] }
        ]
      };

      const result = await slashCommandManager.execute('/mcp list', contextWithServers);
      expect(result.success).toBe(true);
      expect(result.message).toContain('test-server: connected (2 tools)');
    });

    test('命令自动补全', () => {
      const completions = slashCommandManager.getCompletions('/he');
      expect(completions).toContain('/help');

      const allCompletions = slashCommandManager.getCompletions('/');
      expect(allCompletions).toContain('/help');
      expect(allCompletions).toContain('/login');
      expect(allCompletions).toContain('/mode');
    });

    test('无效命令处理', async () => {
      const result = await slashCommandManager.execute('/nonexistent', mockContext);
      expect(result.success).toBe(false);
      expect(result.message).toContain('Unknown command');
    });

    test('命令别名支持', async () => {
      const result = await slashCommandManager.execute('/cls', mockContext);
      expect(result.success).toBe(true);
      expect(result.message).toContain('Conversation history cleared');
    });
  });

  describe('IDE集成测试', () => {
    test('诊断管理器单例模式', () => {
      const instance1 = IdeDiagnosticsManager.getInstance();
      const instance2 = IdeDiagnosticsManager.getInstance();
      expect(instance1).toBe(instance2);
    });

    test('诊断信息比较', () => {
      const manager = IdeDiagnosticsManager.getInstance();
      
      const diag1 = {
        message: 'Test error',
        severity: 1,
        source: 'eslint',
        code: 'E001',
        range: {
          start: { line: 10, character: 5 },
          end: { line: 10, character: 15 }
        }
      };

      const diag2 = { ...diag1 };
      const diag3 = { ...diag1, message: 'Different error' };

      expect(manager['areDiagnosticsEqual'](diag1, diag2)).toBe(true);
      expect(manager['areDiagnosticsEqual'](diag1, diag3)).toBe(false);
    });

    test('文件URI标准化', () => {
      const manager = IdeDiagnosticsManager.getInstance();
      
      expect(manager['normalizeFileUri']('file:///path/to/file.js')).toBe('/path/to/file.js');
      expect(manager['normalizeFileUri']('_claude_fs_right:/path/to/file.js')).toBe('/path/to/file.js');
      expect(manager['normalizeFileUri']('/path/to/file.js')).toBe('/path/to/file.js');
    });

    test('诊断统计计算', () => {
      const manager = IdeDiagnosticsManager.getInstance();
      
      // 模拟一些诊断数据
      manager['baseline'].set('/file1.js', [
        { message: 'Error 1', severity: 1, range: { start: { line: 0, character: 0 }, end: { line: 0, character: 5 } } },
        { message: 'Warning 1', severity: 2, range: { start: { line: 1, character: 0 }, end: { line: 1, character: 5 } } }
      ]);
      
      manager['baseline'].set('/file2.js', [
        { message: 'Info 1', severity: 3, range: { start: { line: 0, character: 0 }, end: { line: 0, character: 5 } } }
      ]);

      const stats = manager.getDiagnosticsStatistics();
      expect(stats.totalFiles).toBe(2);
      expect(stats.totalDiagnostics).toBe(3);
      expect(stats.errorCount).toBe(1);
      expect(stats.warningCount).toBe(1);
      expect(stats.infoCount).toBe(1);
    });
  });

  describe('综合集成测试', () => {
    test('Plan模式 + Steering机制集成', async () => {
      // 进入Plan模式
      planModeManager.setMode('plan', 'integration_test');
      
      // 发送Steering消息
      const handler = new SteeringMessageHandler(planModeManager);
      const message = {
        type: 'user_input' as const,
        content: 'modify the plan to include testing',
        timestamp: Date.now(),
        sessionId: 'test-session',
        planContext: { currentMode: 'plan' }
      };

      const result = await handler.handleMessage(message);
      expect(result.action).toBe('refine_plan');
      expect(planModeManager.isPlanMode()).toBe(true);
    });

    test('特殊模式 + 快捷指令集成', async () => {
      // 笔记模式创建笔记
      specialModeHandler.processInput('# 集成测试笔记 #integration');
      
      // 使用快捷指令查看状态
      const context = {
        sessionId: 'test-session',
        mcpServers: [],
        currentDirectory: '/test',
        planModeManager: planModeManager
      };

      const result = await slashCommandManager.execute('/status', context);
      expect(result.success).toBe(true);

      // 验证笔记已保存
      const notes = specialModeHandler.getNotes();
      expect(notes).toHaveLength(1);
      expect(notes[0].tags).toContain('integration');
    });

    test('完整工作流程模拟', async () => {
      // 1. 进入Plan模式
      planModeManager.setMode('plan', 'workflow_test');
      
      // 2. 使用特殊模式记录笔记
      specialModeHandler.processInput('# 计划：实现新功能 #planning');
      
      // 3. 使用快捷指令检查状态
      const context = {
        sessionId: 'test-session',
        mcpServers: [],
        currentDirectory: '/test',
        planModeManager: planModeManager
      };
      
      let result = await slashCommandManager.execute('/mode', context);
      expect(result.message).toContain('plan');
      
      // 4. 通过Steering批准计划
      const handler = new SteeringMessageHandler(planModeManager);
      const approvalMessage = {
        type: 'plan_approval' as const,
        content: 'approve',
        timestamp: Date.now(),
        sessionId: 'test-session'
      };
      
      const approvalResult = await handler.handleMessage(approvalMessage);
      expect(approvalResult.action).toBe('execute_plan');
      expect(planModeManager.getCurrentMode()).toBe('default');
      
      // 5. 验证最终状态
      result = await slashCommandManager.execute('/status', context);
      expect(result.message).toContain('default');
    });
  });
});
```

---

## 📋 阶段3完成验证清单

### 功能验证项目

**Plan模式系统** ✅
- [ ] wj2状态机循环功能正常
- [ ] Shift+Tab键切换工作正常
- [ ] Plan模式UI指示器显示正确
- [ ] exit_plan_mode工具正常工作
- [ ] 系统提醒注入机制生效

**实时Steering机制** ✅
- [ ] h2A消息队列集成Plan模式
- [ ] stdin监听捕获用户输入
- [ ] Plan模式下的特殊命令处理
- [ ] Steering消息类型正确分类
- [ ] 用户引导响应及时

**特殊交互模式** ✅
- [ ] !bash模式直接执行命令
- [ ] #笔记模式记录和搜索
- [ ] 多行输入模式正常工作
- [ ] 模式状态正确显示
- [ ] 模式切换流畅

**快捷指令系统** ✅
- [ ] 15+斜杠命令全部实现
- [ ] 命令自动补全功能
- [ ] 参数解析和验证
- [ ] 错误处理和帮助信息
- [ ] 命令别名支持

**IDE集成机制** ✅
- [ ] PK诊断管理器正常工作
- [ ] LSP协议集成成功
- [ ] 诊断信息比较算法准确
- [ ] MCP工具白名单机制
- [ ] IDE连接检测功能

### 性能验证项目

**响应性能** ✅
- [ ] 模式切换响应 < 100ms
- [ ] Steering消息处理 < 200ms
- [ ] 快捷指令执行 < 500ms
- [ ] 诊断信息获取 < 1s
- [ ] UI更新流畅无卡顿

**内存使用** ✅
- [ ] Plan模式状态占用 < 10MB
- [ ] Steering队列缓冲 < 50MB
- [ ] 诊断信息缓存 < 100MB
- [ ] 总体内存增长 < 200MB

**并发处理** ✅
- [ ] 多模式同时运行稳定
- [ ] Steering消息不丢失
- [ ] 快捷指令不冲突
- [ ] IDE集成不阻塞主流程

### 质量验证项目

**代码质量** ✅
- [ ] TypeScript类型覆盖 > 95%
- [ ] 单元测试覆盖 > 80%
- [ ] 集成测试通过率 100%
- [ ] 代码复杂度 < 10
- [ ] 无ESLint警告错误

**用户体验** ✅
- [ ] 操作直观易懂
- [ ] 错误提示友好
- [ ] 功能发现性好
- [ ] 帮助文档完整
- [ ] 键盘快捷键高效

**兼容性** ✅
- [ ] Node.js 18+ 支持
- [ ] 主流IDE兼容
- [ ] 多操作系统支持
- [ ] 终端环境适配
- [ ] MCP协议标准合规

---

## 🎯 下一阶段预告

阶段3完成后，Open Claude Code将具备：

1. **完整的高级交互能力**：
   - Plan模式安全分析
   - 实时用户引导
   - 特殊模式处理
   - 快捷指令系统

2. **IDE深度集成能力**：
   - LSP诊断信息
   - 代码执行环境
   - 实时状态同步
   - MCP协议支持

3. **优秀的用户体验**：
   - 直观的UI指示
   - 流畅的交互响应
   - 完善的帮助系统
   - 高效的快捷操作

**进入阶段4**：MCP集成和扩展系统（4周）
- 完整MCP协议实现
- 多传输方式支持
- 插件生态系统
- 第三方工具集成

这标志着Open Claude Code在高级特性实现上的重大突破，为后续的MCP集成和扩展奠定了坚实基础。