📄 generator.ts  •  7809 bytes
/**
 * 执行计划 - 计划生成器
 * Phase 2: LLM生成 + 智能拆解
 */
import { type ExecutionPlan, type PlanStep, type Risk评估 } from './types'

/** 生成唯一ID */
function generateId(): string {
  return 'plan_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 6)
}

/** 分析任务复杂度 */
function analyzeComplexity(task: string): 'simple' | 'medium' | 'complex' {
  const simpleIndicators = ['读', '查看', '显示', '输出', '列出']
  const complexIndicators = ['创建', '实现', '开发', '系统', '完整', '全面']
  
  let score = 0
  for (const ind of simpleIndicators) {
    if (task.includes(ind)) score -= 1
  }
  for (const ind of complexIndicators) {
    if (task.includes(ind)) score += 2
  }
  
  if (score <= -1) return 'simple'
  if (score >= 2) return 'complex'
  return 'medium'
}

/** 识别文件路径 */
function extractFilePaths(task: string): string[] {
  const regex = /[\w\-\./]+\.[a-zA-Z]+/g
  return task.match(regex) || []
}

/** 识别编程语言 */
function extractLanguage(task: string): string | null {
  const langMap: Record<string, RegExp> = {
    'TypeScript': /typescript|ts\b/i,
    'JavaScript': /javascript|js\b/i,
    'Python': /python|py\b/i,
    'Rust': /rust\b/i,
    'Go': /\bgo\b/i,
    'HTML': /html\b/i,
    'CSS': /css\b/i,
    'SQL': /sql\b/i,
  }
  
  for (const [lang, regex] of Object.entries(langMap)) {
    if (regex.test(task)) return lang
  }
  return null
}

/** 为简单任务生成快速计划 */
function generateSimplePlan(task: string): ExecutionPlan {
  const filePaths = extractFilePaths(task)
  const lang = extractLanguage(task)
  const steps: PlanStep[] = []
  
  let stepId = 1
  
  // 根据任务关键词生成步骤
  if (task.includes('读') || task.includes('查看') || task.includes('显示')) {
    for (const file of filePaths) {
      steps.push({
        id: stepId++,
        action: `读取文件 ${file}`,
        tool: 'file_read',
        params: { path: file },
        expected: '文件内容',
        status: 'pending',
        retryCount: 0,
      })
    }
    if (steps.length === 0) {
      steps.push({
        id: stepId++,
        action: '搜索相关信息',
        tool: 'grep_search',
        params: { pattern: task.replace(/[读查看显示]/g, '').trim() },
        expected: '搜索结果',
        status: 'pending',
        retryCount: 0,
      })
    }
  } else if (task.includes('写') || task.includes('创建') || task.includes('新建')) {
    const file = filePaths[0] || 'new_file.txt'
    steps.push({
      id: stepId++,
      action: `创建文件 ${file}`,
      tool: 'file_write',
      params: { path: file, content: `// ${lang || 'TODO'}: ${task}` },
      expected: '文件创建成功',
      status: 'pending',
      retryCount: 0,
    })
  }
  
  return {
    id: generateId(),
    title: task.slice(0, 50),
    description: task,
    steps,
    estimatedSteps: steps.length,
    risks: [{ level: 'low', description: '简单文件操作' }],
    createdAt: new Date().toISOString(),
    status: 'pending',
    currentStep: 0,
  }
}

/** 为中等任务生成计划 */
function generateMediumPlan(task: string): ExecutionPlan {
  const filePaths = extractFilePaths(task)
  const lang = extractLanguage(task)
  const steps: PlanStep[] = []
  
  let stepId = 1
  
  // 1. 分析现有代码
  if (filePaths.length > 0) {
    steps.push({
      id: stepId++,
      action: `分析文件 ${filePaths[0]}`,
      tool: 'file_read',
      params: { path: filePaths[0] },
      expected: '代码结构分析',
      status: 'pending',
      retryCount: 0,
    })
  }
  
  // 2. 编写代码
  const targetFile = filePaths[1] || filePaths[0] || 'output.ts'
  steps.push({
    id: stepId++,
    action: `编写 ${lang || '代码'} 代码`,
    tool: 'file_write',
    params: { path: targetFile, content: '// generated code' },
    expected: '代码编写完成',
    status: 'pending',
    retryCount: 0,
  })
  
  // 3. 验证语法
  if (lang === 'TypeScript') {
    steps.push({
      id: stepId++,
      action: '检查 TypeScript 语法',
      tool: 'bash_run',
      params: { command: `npx tsc --noEmit ${targetFile}` },
      expected: '无语法错误',
      status: 'pending',
      retryCount: 1,
    })
  }
  
  return {
    id: generateId(),
    title: task.slice(0, 50),
    description: task,
    steps,
    estimatedSteps: steps.length,
    estimatedTime: steps.length * 5,
    risks: [{ level: 'medium', description: '涉及代码修改' }],
    createdAt: new Date().toISOString(),
    status: 'pending',
    currentStep: 0,
  }
}

/** 为复杂任务生成计划 */
function generateComplexPlan(task: string): ExecutionPlan {
  const filePaths = extractFilePaths(task)
  const lang = extractLanguage(task)
  const steps: PlanStep[] = []
  
  let stepId = 1
  
  // 1. 调研阶段
  steps.push({
    id: stepId++,
    action: '分析任务需求',
    tool: 'list_dir',
    params: { path: '.' },
    expected: '了解项目结构',
    status: 'pending',
    retryCount: 0,
  })
  
  // 2. 读取现有代码
  for (const file of filePaths.slice(0, 3)) {
    steps.push({
      id: stepId++,
      action: `分析 ${file}`,
      tool: 'file_read',
      params: { path: file },
      expected: '理解现有实现',
      status: 'pending',
      retryCount: 0,
    })
  }
  
  // 3. 实现阶段
  steps.push({
    id: stepId++,
    action: `实现 ${lang || '代码'} 功能`,
    tool: 'file_write',
    params: { path: 'src/main.ts', content: '// implementation' },
    expected: '功能实现完成',
    status: 'pending',
    retryCount: 2,
  })
  
  // 4. 测试阶段
  steps.push({
    id: stepId++,
    action: '运行测试验证',
    tool: 'bash_run',
    params: { command: 'npm test' },
    expected: '测试通过',
    status: 'pending',
    retryCount: 1,
  })
  
  return {
    id: generateId(),
    title: task.slice(0, 50),
    description: task,
    steps,
    estimatedSteps: steps.length,
    estimatedTime: steps.length * 10,
    risks: [
      { level: 'medium', description: '涉及多文件修改', mitigation: '分步执行验证' },
      { level: 'medium', description: '可能影响现有功能', mitigation: '执行测试确认' },
    ],
    createdAt: new Date().toISOString(),
    status: 'pending',
    currentStep: 0,
  }
}

/**
 * 生成执行计划
 * @param task 用户任务描述
 * @returns 执行计划
 */
export function generatePlan(task: string): ExecutionPlan {
  const complexity = analyzeComplexity(task)
  
  switch (complexity) {
    case 'simple':
      return generateSimplePlan(task)
    case 'medium':
      return generateMediumPlan(task)
    case 'complex':
      return generateComplexPlan(task)
  }
}

/**
 * 格式化计划为用户可读文本
 */
export function formatPlan(plan: ExecutionPlan): string {
  let output = `\n📋 **执行计划**: ${plan.title}\n\n`
  output += `⏱️ 预估步骤: ${plan.estimatedSteps}`
  if (plan.estimatedTime) {
    output += ` | 预估时间: ~${plan.estimatedTime}秒`
  }
  output += '\n\n'
  
  for (const step of plan.steps) {
    output += `${step.id}. [${step.status}] ${step.action}\n`
    output += `   🔧 ${step.tool}\n`
    output += `   📤 预期: ${step.expected}\n\n`
  }
  
  if (plan.risks.length > 0) {
    output += '\n⚠️ **风险提示**:\n'
    for (const risk of plan.risks) {
      output += `- ${risk.level.toUpperCase()}: ${risk.description}`
      if (risk.mitigation) {
        output += ` (${risk.mitigation})`
      }
      output += '\n'
    }
  }
  
  output += '\n---\n'
  output += '请选择操作:\n'
  output += '1️⃣ 确认执行\n'
  output += '2️⃣ 修改计划\n'
  output += '3️⃣ 部分执行\n'
  output += '4️⃣ 取消\n'
  
  return output
}