Skip to content

任务 API

概述

Trae 任务 API 提供了强大的任务管理和执行系统,允许开发者定义、配置和运行各种类型的任务。任务系统支持构建脚本、测试运行、部署流程等自动化操作。

核心概念

任务定义

typescript
interface TaskDefinition {
  readonly type: string;
  readonly required?: string[];
  readonly properties?: {
    [property: string]: {
      type: string;
      description?: string;
      default?: any;
      enum?: any[];
    };
  };
}

interface Task {
  readonly definition: TaskDefinition;
  readonly scope: TaskScope;
  readonly name?: string;
  readonly source: string;
  readonly execution?: TaskExecution;
  readonly group?: TaskGroup;
  readonly presentationOptions?: TaskPresentationOptions;
  readonly problemMatchers?: string[];
  readonly runOptions?: RunOptions;
  readonly detail?: string;
}

enum TaskScope {
  Global = 1,
  Workspace = 2,
  WorkspaceFolder = 3
}

interface TaskExecution {
  // 基础执行接口
}

interface ShellExecution extends TaskExecution {
  readonly commandLine?: string;
  readonly command?: string | ShellQuotedString;
  readonly args?: (string | ShellQuotedString)[];
  readonly options?: ShellExecutionOptions;
}

interface ProcessExecution extends TaskExecution {
  readonly process: string;
  readonly args?: string[];
  readonly options?: ProcessExecutionOptions;
}

interface CustomExecution extends TaskExecution {
  readonly callback: (resolvedDefinition: TaskDefinition) => Thenable<Pseudoterminal>;
}

任务组和呈现

typescript
interface TaskGroup {
  readonly id: string;
  readonly label?: string;
  readonly isDefault?: boolean;
}

class TaskGroup {
  static readonly Clean: TaskGroup;
  static readonly Build: TaskGroup;
  static readonly Rebuild: TaskGroup;
  static readonly Test: TaskGroup;
}

interface TaskPresentationOptions {
  readonly reveal?: TaskRevealKind;
  readonly echo?: boolean;
  readonly focus?: boolean;
  readonly panel?: TaskPanelKind;
  readonly showReuseMessage?: boolean;
  readonly clear?: boolean;
  readonly group?: string;
  readonly close?: boolean;
}

enum TaskRevealKind {
  Always = 1,
  Silent = 2,
  Never = 3
}

enum TaskPanelKind {
  Shared = 1,
  Dedicated = 2,
  New = 3
}

API 参考

任务管理

任务注册和执行

typescript
import { tasks, Task, TaskDefinition, ShellExecution } from '@trae/api';

// 注册任务提供者
const registerTaskProvider = (
  type: string,
  provider: TaskProvider
): Disposable => {
  return tasks.registerTaskProvider(type, provider);
};

// 获取任务
const getTasks = async (filter?: TaskFilter): Promise<Task[]> => {
  return await tasks.fetchTasks(filter);
};

// 执行任务
const executeTask = async (task: Task): Promise<TaskExecution> => {
  return await tasks.executeTask(task);
};

// 终止任务
const terminateTask = async (execution: TaskExecution): Promise<void> => {
  await tasks.terminateTask(execution);
};

// 获取活动任务
const getActiveTasks = (): TaskExecution[] => {
  return tasks.taskExecutions;
};

// 监听任务事件
const onDidStartTask = (listener: (e: TaskStartEvent) => void): Disposable => {
  return tasks.onDidStartTask(listener);
};

const onDidEndTask = (listener: (e: TaskEndEvent) => void): Disposable => {
  return tasks.onDidEndTask(listener);
};

const onDidStartTaskProcess = (
  listener: (e: TaskProcessStartEvent) => void
): Disposable => {
  return tasks.onDidStartTaskProcess(listener);
};

const onDidEndTaskProcess = (
  listener: (e: TaskProcessEndEvent) => void
): Disposable => {
  return tasks.onDidEndTaskProcess(listener);
};

任务提供者实现

typescript
interface TaskProvider {
  provideTasks(token?: CancellationToken): ProviderResult<Task[]>;
  resolveTask?(task: Task, token?: CancellationToken): ProviderResult<Task>;
}

class CustomTaskProvider implements TaskProvider {
  private tasks: Task[] = [];
  
  constructor() {
    this.initializeTasks();
  }
  
  provideTasks(token?: CancellationToken): Task[] {
    return this.tasks;
  }
  
  resolveTask(task: Task, token?: CancellationToken): Task | undefined {
    // 解析任务的具体实现
    const definition = task.definition;
    
    if (definition.type === 'custom-build') {
      return this.createBuildTask(definition);
    }
    
    if (definition.type === 'custom-test') {
      return this.createTestTask(definition);
    }
    
    return undefined;
  }
  
  private initializeTasks(): void {
    // 构建任务
    this.tasks.push(this.createBuildTask({
      type: 'custom-build',
      target: 'production'
    }));
    
    // 测试任务
    this.tasks.push(this.createTestTask({
      type: 'custom-test',
      suite: 'unit'
    }));
    
    // 清理任务
    this.tasks.push(this.createCleanTask());
    
    // 部署任务
    this.tasks.push(this.createDeployTask());
  }
  
  private createBuildTask(definition: any): Task {
    const execution = new ShellExecution(
      'npm',
      ['run', 'build'],
      {
        cwd: workspace.rootPath,
        env: {
          NODE_ENV: definition.target || 'development'
        }
      }
    );
    
    const task = new Task(
      definition,
      TaskScope.Workspace,
      'Build Project',
      'custom-build',
      execution,
      ['$tsc', '$eslint']
    );
    
    task.group = TaskGroup.Build;
    task.presentationOptions = {
      reveal: TaskRevealKind.Always,
      echo: true,
      focus: false,
      panel: TaskPanelKind.Shared,
      showReuseMessage: true,
      clear: false
    };
    
    return task;
  }
  
  private createTestTask(definition: any): Task {
    const args = ['test'];
    
    if (definition.suite) {
      args.push('--', '--grep', definition.suite);
    }
    
    const execution = new ShellExecution('npm', args, {
      cwd: workspace.rootPath
    });
    
    const task = new Task(
      definition,
      TaskScope.Workspace,
      `Run ${definition.suite || 'All'} Tests`,
      'custom-test',
      execution,
      ['$jest', '$mocha']
    );
    
    task.group = TaskGroup.Test;
    task.presentationOptions = {
      reveal: TaskRevealKind.Always,
      echo: true,
      focus: true,
      panel: TaskPanelKind.Dedicated,
      clear: true
    };
    
    return task;
  }
  
  private createCleanTask(): Task {
    const execution = new ShellExecution('rm', ['-rf', 'dist', 'build'], {
      cwd: workspace.rootPath
    });
    
    const task = new Task(
      { type: 'custom-clean' },
      TaskScope.Workspace,
      'Clean Build Artifacts',
      'custom-clean',
      execution
    );
    
    task.group = TaskGroup.Clean;
    task.presentationOptions = {
      reveal: TaskRevealKind.Silent,
      echo: false
    };
    
    return task;
  }
  
  private createDeployTask(): Task {
    const execution = new CustomExecution(async (definition) => {
      return new DeploymentPseudoterminal(definition);
    });
    
    const task = new Task(
      { type: 'custom-deploy' },
      TaskScope.Workspace,
      'Deploy Application',
      'custom-deploy',
      execution
    );
    
    task.presentationOptions = {
      reveal: TaskRevealKind.Always,
      echo: true,
      focus: true,
      panel: TaskPanelKind.New
    };
    
    return task;
  }
}

自定义任务执行

伪终端实现

typescript
class DeploymentPseudoterminal implements Pseudoterminal {
  private writeEmitter = new EventEmitter<string>();
  private closeEmitter = new EventEmitter<number | void>();
  
  onDidWrite: Event<string> = this.writeEmitter.event;
  onDidClose: Event<number | void> = this.closeEmitter.event;
  
  constructor(private definition: TaskDefinition) {}
  
  open(initialDimensions: TerminalDimensions | undefined): void {
    this.writeEmitter.fire('Starting deployment...\r\n');
    this.deploy();
  }
  
  close(): void {
    // 清理资源
  }
  
  handleInput(data: string): void {
    // 处理用户输入
    if (data === '\r') {
      this.writeEmitter.fire('\r\n');
    } else {
      this.writeEmitter.fire(data);
    }
  }
  
  setDimensions(dimensions: TerminalDimensions): void {
    // 处理终端尺寸变化
  }
  
  private async deploy(): Promise<void> {
    try {
      // 步骤 1: 构建项目
      this.writeEmitter.fire('Step 1: Building project...\r\n');
      await this.runStep('npm run build', 'Build completed successfully');
      
      // 步骤 2: 运行测试
      this.writeEmitter.fire('Step 2: Running tests...\r\n');
      await this.runStep('npm test', 'All tests passed');
      
      // 步骤 3: 部署到服务器
      this.writeEmitter.fire('Step 3: Deploying to server...\r\n');
      await this.deployToServer();
      
      this.writeEmitter.fire('\r\n✅ Deployment completed successfully!\r\n');
      this.closeEmitter.fire(0);
    } catch (error) {
      this.writeEmitter.fire(`\r\n❌ Deployment failed: ${error.message}\r\n`);
      this.closeEmitter.fire(1);
    }
  }
  
  private async runStep(command: string, successMessage: string): Promise<void> {
    return new Promise((resolve, reject) => {
      const process = spawn(command, { shell: true });
      
      process.stdout.on('data', (data) => {
        this.writeEmitter.fire(data.toString());
      });
      
      process.stderr.on('data', (data) => {
        this.writeEmitter.fire(data.toString());
      });
      
      process.on('close', (code) => {
        if (code === 0) {
          this.writeEmitter.fire(`${successMessage}\r\n`);
          resolve();
        } else {
          reject(new Error(`Command failed with exit code ${code}`));
        }
      });
    });
  }
  
  private async deployToServer(): Promise<void> {
    // 模拟部署过程
    const steps = [
      'Connecting to server...',
      'Uploading files...',
      'Installing dependencies...',
      'Restarting services...',
      'Verifying deployment...'
    ];
    
    for (const step of steps) {
      this.writeEmitter.fire(`${step}\r\n`);
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }
}

任务配置

tasks.json 配置

typescript
// .vscode/tasks.json 示例
{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "shell",
      "label": "Build Project",
      "command": "npm",
      "args": ["run", "build"],
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "presentation": {
        "echo": true,
        "reveal": "always",
        "focus": false,
        "panel": "shared",
        "showReuseMessage": true,
        "clear": false
      },
      "problemMatcher": ["$tsc", "$eslint"],
      "options": {
        "cwd": "${workspaceFolder}",
        "env": {
          "NODE_ENV": "production"
        }
      }
    },
    {
      "type": "shell",
      "label": "Run Tests",
      "command": "npm",
      "args": ["test"],
      "group": "test",
      "presentation": {
        "echo": true,
        "reveal": "always",
        "focus": true,
        "panel": "dedicated",
        "clear": true
      },
      "problemMatcher": ["$jest"],
      "runOptions": {
        "runOn": "folderOpen"
      }
    },
    {
      "type": "process",
      "label": "Watch Files",
      "command": "node",
      "args": ["scripts/watch.js"],
      "isBackground": true,
      "presentation": {
        "reveal": "never"
      },
      "problemMatcher": {
        "pattern": {
          "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
          "file": 1,
          "line": 2,
          "column": 3,
          "severity": 4,
          "message": 5
        },
        "background": {
          "activeOnStart": true,
          "beginsPattern": "^\\[.*\\] Starting compilation",
          "endsPattern": "^\\[.*\\] Compilation complete"
        }
      }
    },
    {
      "type": "custom-deploy",
      "label": "Deploy to Production",
      "target": "production",
      "options": {
        "server": "prod.example.com",
        "path": "/var/www/app"
      },
      "dependsOn": ["Build Project", "Run Tests"]
    }
  ]
}

// 任务配置管理
class TaskConfigurationManager {
  private configPath: string;
  
  constructor(workspaceFolder: WorkspaceFolder) {
    this.configPath = path.join(workspaceFolder.uri.fsPath, '.vscode', 'tasks.json');
  }
  
  async loadConfiguration(): Promise<TaskConfiguration> {
    try {
      const content = await workspace.fs.readFile(Uri.file(this.configPath));
      return JSON.parse(content.toString());
    } catch (error) {
      return { version: '2.0.0', tasks: [] };
    }
  }
  
  async saveConfiguration(config: TaskConfiguration): Promise<void> {
    const content = JSON.stringify(config, null, 2);
    await workspace.fs.writeFile(Uri.file(this.configPath), Buffer.from(content));
  }
  
  async addTask(task: TaskDefinitionConfig): Promise<void> {
    const config = await this.loadConfiguration();
    config.tasks.push(task);
    await this.saveConfiguration(config);
  }
  
  async removeTask(label: string): Promise<void> {
    const config = await this.loadConfiguration();
    config.tasks = config.tasks.filter(task => task.label !== label);
    await this.saveConfiguration(config);
  }
  
  async updateTask(label: string, updates: Partial<TaskDefinitionConfig>): Promise<void> {
    const config = await this.loadConfiguration();
    const taskIndex = config.tasks.findIndex(task => task.label === label);
    
    if (taskIndex !== -1) {
      config.tasks[taskIndex] = { ...config.tasks[taskIndex], ...updates };
      await this.saveConfiguration(config);
    }
  }
}

interface TaskConfiguration {
  version: string;
  tasks: TaskDefinitionConfig[];
}

interface TaskDefinitionConfig {
  type: string;
  label: string;
  command?: string;
  args?: string[];
  group?: string | { kind: string; isDefault?: boolean };
  presentation?: TaskPresentationOptions;
  problemMatcher?: string | string[];
  options?: {
    cwd?: string;
    env?: Record<string, string>;
    shell?: {
      executable?: string;
      args?: string[];
    };
  };
  dependsOn?: string | string[];
  runOptions?: {
    runOn?: 'default' | 'folderOpen';
  };
  isBackground?: boolean;
  [key: string]: any;
}

问题匹配器

内置问题匹配器

typescript
// 常用问题匹配器
const problemMatchers = {
  // TypeScript 编译器
  '$tsc': {
    owner: 'typescript',
    fileLocation: 'relative',
    pattern: {
      regexp: '^([^\\s].*)\\((\\d+),(\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$',
      file: 1,
      line: 2,
      column: 3,
      severity: 4,
      code: 5,
      message: 6
    }
  },
  
  // ESLint
  '$eslint-compact': {
    owner: 'eslint',
    fileLocation: 'relative',
    pattern: {
      regexp: '^(.+):\\s+line\\s+(\\d+),\\s+col\\s+(\\d+),\\s+(Error|Warning|Info)\\s+-\\s+(.+)\\s+\\((.+)\\)$',
      file: 1,
      line: 2,
      column: 3,
      severity: 4,
      message: 5,
      code: 6
    }
  },
  
  // Jest 测试
  '$jest': {
    owner: 'jest',
    fileLocation: 'relative',
    pattern: [
      {
        regexp: '^\\s*FAIL\\s+(.*)$',
        file: 1
      },
      {
        regexp: '^\\s+●\\s+(.*)$',
        message: 1
      },
      {
        regexp: '^\\s+at\\s+.*\\s+\\((.*):(\\d+):(\\d+)\\)$',
        file: 1,
        line: 2,
        column: 3,
        loop: true
      }
    ]
  }
};

// 自定义问题匹配器
class CustomProblemMatcher {
  static create(name: string, config: ProblemMatcherConfig): ProblemMatcher {
    return {
      name,
      owner: config.owner,
      fileLocation: config.fileLocation || 'relative',
      pattern: config.pattern,
      background: config.background,
      watching: config.watching
    };
  }
  
  static registerCustomMatchers(): void {
    // 注册自定义构建工具的问题匹配器
    const webpackMatcher = this.create('$webpack', {
      owner: 'webpack',
      fileLocation: 'relative',
      pattern: {
        regexp: '^ERROR in (.*)\\((\\d+),(\\d+)\\): (.*)$',
        file: 1,
        line: 2,
        column: 3,
        message: 4
      }
    });
    
    // 注册 Sass 编译器问题匹配器
    const sassMatcher = this.create('$sass', {
      owner: 'sass',
      fileLocation: 'relative',
      pattern: {
        regexp: '^Error: (.*)\\s+on line (\\d+) of (.*)$',
        message: 1,
        line: 2,
        file: 3
      }
    });
  }
}

interface ProblemMatcherConfig {
  owner: string;
  fileLocation?: 'absolute' | 'relative';
  pattern: ProblemPattern | ProblemPattern[];
  background?: BackgroundMatcher;
  watching?: WatchingMatcher;
}

interface ProblemPattern {
  regexp: string;
  file?: number;
  line?: number;
  column?: number;
  severity?: number;
  message?: number;
  code?: number;
  loop?: boolean;
}

interface BackgroundMatcher {
  activeOnStart?: boolean;
  beginsPattern?: string;
  endsPattern?: string;
}

interface WatchingMatcher {
  activeOnStart?: boolean;
  beginsPattern?: string;
  endsPattern?: string;
}

任务监控和管理

任务执行监控

typescript
class TaskMonitor {
  private activeExecutions: Map<string, TaskExecutionInfo> = new Map();
  private executionHistory: TaskExecutionInfo[] = [];
  private disposables: Disposable[] = [];
  
  constructor() {
    this.setupEventListeners();
  }
  
  private setupEventListeners(): void {
    this.disposables.push(
      tasks.onDidStartTask(event => {
        this.onTaskStarted(event);
      }),
      
      tasks.onDidEndTask(event => {
        this.onTaskEnded(event);
      }),
      
      tasks.onDidStartTaskProcess(event => {
        this.onTaskProcessStarted(event);
      }),
      
      tasks.onDidEndTaskProcess(event => {
        this.onTaskProcessEnded(event);
      })
    );
  }
  
  private onTaskStarted(event: TaskStartEvent): void {
    const info: TaskExecutionInfo = {
      execution: event.execution,
      task: event.execution.task,
      startTime: Date.now(),
      status: 'running',
      processId: undefined,
      exitCode: undefined
    };
    
    this.activeExecutions.set(this.getExecutionId(event.execution), info);
    this.notifyTaskStarted(info);
  }
  
  private onTaskEnded(event: TaskEndEvent): void {
    const executionId = this.getExecutionId(event.execution);
    const info = this.activeExecutions.get(executionId);
    
    if (info) {
      info.endTime = Date.now();
      info.duration = info.endTime - info.startTime;
      info.status = 'completed';
      
      this.activeExecutions.delete(executionId);
      this.executionHistory.push(info);
      
      // 保持历史记录在合理范围内
      if (this.executionHistory.length > 100) {
        this.executionHistory = this.executionHistory.slice(-50);
      }
      
      this.notifyTaskEnded(info);
    }
  }
  
  private onTaskProcessStarted(event: TaskProcessStartEvent): void {
    const executionId = this.getExecutionId(event.execution);
    const info = this.activeExecutions.get(executionId);
    
    if (info) {
      info.processId = event.processId;
    }
  }
  
  private onTaskProcessEnded(event: TaskProcessEndEvent): void {
    const executionId = this.getExecutionId(event.execution);
    const info = this.activeExecutions.get(executionId);
    
    if (info) {
      info.exitCode = event.exitCode;
    }
  }
  
  private getExecutionId(execution: TaskExecution): string {
    return `${execution.task.source}-${execution.task.name || execution.task.definition.type}`;
  }
  
  private notifyTaskStarted(info: TaskExecutionInfo): void {
    window.showInformationMessage(
      `Task started: ${info.task.name || info.task.definition.type}`,
      'Show Terminal'
    ).then(action => {
      if (action === 'Show Terminal') {
        // 显示任务终端
      }
    });
  }
  
  private notifyTaskEnded(info: TaskExecutionInfo): void {
    const duration = info.duration ? `(${info.duration}ms)` : '';
    const message = `Task completed: ${info.task.name || info.task.definition.type} ${duration}`;
    
    if (info.exitCode === 0) {
      window.showInformationMessage(message);
    } else {
      window.showErrorMessage(`Task failed: ${info.task.name || info.task.definition.type}`);
    }
  }
  
  getActiveExecutions(): TaskExecutionInfo[] {
    return Array.from(this.activeExecutions.values());
  }
  
  getExecutionHistory(): TaskExecutionInfo[] {
    return [...this.executionHistory];
  }
  
  getTaskStatistics(): TaskStatistics {
    const total = this.executionHistory.length;
    const successful = this.executionHistory.filter(info => info.exitCode === 0).length;
    const failed = total - successful;
    
    const durations = this.executionHistory
      .filter(info => info.duration !== undefined)
      .map(info => info.duration!);
    
    const averageDuration = durations.length > 0 
      ? durations.reduce((sum, duration) => sum + duration, 0) / durations.length
      : 0;
    
    return {
      total,
      successful,
      failed,
      averageDuration,
      successRate: total > 0 ? (successful / total) * 100 : 0
    };
  }
  
  dispose(): void {
    this.disposables.forEach(d => d.dispose());
  }
}

interface TaskExecutionInfo {
  execution: TaskExecution;
  task: Task;
  startTime: number;
  endTime?: number;
  duration?: number;
  status: 'running' | 'completed' | 'failed';
  processId?: number;
  exitCode?: number;
}

interface TaskStatistics {
  total: number;
  successful: number;
  failed: number;
  averageDuration: number;
  successRate: number;
}

任务模板和生成器

任务模板系统

typescript
class TaskTemplateManager {
  private templates: Map<string, TaskTemplate> = new Map();
  
  constructor() {
    this.initializeBuiltinTemplates();
  }
  
  private initializeBuiltinTemplates(): void {
    // Node.js 项目模板
    this.registerTemplate('nodejs', {
      name: 'Node.js Project',
      description: 'Common tasks for Node.js projects',
      tasks: [
        {
          type: 'shell',
          label: 'npm: install',
          command: 'npm',
          args: ['install'],
          group: 'build',
          presentation: { reveal: 'always' }
        },
        {
          type: 'shell',
          label: 'npm: build',
          command: 'npm',
          args: ['run', 'build'],
          group: { kind: 'build', isDefault: true },
          problemMatcher: ['$tsc']
        },
        {
          type: 'shell',
          label: 'npm: test',
          command: 'npm',
          args: ['test'],
          group: 'test',
          problemMatcher: ['$jest']
        },
        {
          type: 'shell',
          label: 'npm: start',
          command: 'npm',
          args: ['start'],
          isBackground: true,
          problemMatcher: {
            pattern: {
              regexp: '^.*$'
            },
            background: {
              activeOnStart: true,
              beginsPattern: '^.*Server starting.*$',
              endsPattern: '^.*Server started.*$'
            }
          }
        }
      ]
    });
    
    // Python 项目模板
    this.registerTemplate('python', {
      name: 'Python Project',
      description: 'Common tasks for Python projects',
      tasks: [
        {
          type: 'shell',
          label: 'pip: install requirements',
          command: 'pip',
          args: ['install', '-r', 'requirements.txt'],
          group: 'build'
        },
        {
          type: 'shell',
          label: 'python: run tests',
          command: 'python',
          args: ['-m', 'pytest'],
          group: 'test',
          problemMatcher: {
            pattern: {
              regexp: '^(.*):(\\d+): (.*)$',
              file: 1,
              line: 2,
              message: 3
            }
          }
        },
        {
          type: 'shell',
          label: 'python: lint',
          command: 'flake8',
          args: ['.'],
          group: 'build',
          problemMatcher: {
            pattern: {
              regexp: '^(.*):(\\d+):(\\d+): ([EW]\\d+) (.*)$',
              file: 1,
              line: 2,
              column: 3,
              code: 4,
              message: 5
            }
          }
        }
      ]
    });
  }
  
  registerTemplate(id: string, template: TaskTemplate): void {
    this.templates.set(id, template);
  }
  
  getTemplate(id: string): TaskTemplate | undefined {
    return this.templates.get(id);
  }
  
  getAllTemplates(): TaskTemplate[] {
    return Array.from(this.templates.values());
  }
  
  async generateTasksFromTemplate(
    templateId: string,
    workspaceFolder: WorkspaceFolder,
    options: TemplateOptions = {}
  ): Promise<void> {
    const template = this.getTemplate(templateId);
    if (!template) {
      throw new Error(`Template ${templateId} not found`);
    }
    
    const configManager = new TaskConfigurationManager(workspaceFolder);
    const config = await configManager.loadConfiguration();
    
    // 应用模板变量替换
    const processedTasks = template.tasks.map(task => 
      this.processTaskTemplate(task, options)
    );
    
    // 添加任务到配置
    config.tasks.push(...processedTasks);
    
    await configManager.saveConfiguration(config);
    
    window.showInformationMessage(
      `Generated ${processedTasks.length} tasks from ${template.name} template`
    );
  }
  
  private processTaskTemplate(
    task: TaskDefinitionConfig,
    options: TemplateOptions
  ): TaskDefinitionConfig {
    const processed = { ...task };
    
    // 替换模板变量
    if (typeof processed.command === 'string') {
      processed.command = this.replaceVariables(processed.command, options);
    }
    
    if (processed.args) {
      processed.args = processed.args.map(arg => 
        this.replaceVariables(arg, options)
      );
    }
    
    if (processed.label) {
      processed.label = this.replaceVariables(processed.label, options);
    }
    
    return processed;
  }
  
  private replaceVariables(text: string, options: TemplateOptions): string {
    let result = text;
    
    // 替换内置变量
    result = result.replace(/\${workspaceFolder}/g, '${workspaceFolder}');
    result = result.replace(/\${workspaceFolderBasename}/g, '${workspaceFolderBasename}');
    
    // 替换自定义变量
    if (options.variables) {
      for (const [key, value] of Object.entries(options.variables)) {
        result = result.replace(new RegExp(`\\$\\{${key}\\}`, 'g'), value);
      }
    }
    
    return result;
  }
}

interface TaskTemplate {
  name: string;
  description: string;
  tasks: TaskDefinitionConfig[];
  variables?: TemplateVariable[];
}

interface TemplateVariable {
  name: string;
  description: string;
  default?: string;
  type: 'string' | 'boolean' | 'choice';
  choices?: string[];
}

interface TemplateOptions {
  variables?: Record<string, string>;
}

最佳实践

任务组织

typescript
// 1. 任务分组和依赖
class TaskOrganizer {
  static createBuildPipeline(): TaskDefinitionConfig[] {
    return [
      {
        type: 'shell',
        label: 'Clean',
        command: 'rm',
        args: ['-rf', 'dist'],
        group: 'build',
        presentation: { reveal: 'silent' }
      },
      {
        type: 'shell',
        label: 'Compile TypeScript',
        command: 'tsc',
        group: 'build',
        dependsOn: 'Clean',
        problemMatcher: '$tsc'
      },
      {
        type: 'shell',
        label: 'Bundle Assets',
        command: 'webpack',
        group: 'build',
        dependsOn: 'Compile TypeScript',
        problemMatcher: '$webpack'
      },
      {
        type: 'shell',
        label: 'Build All',
        command: 'echo',
        args: ['Build completed'],
        group: { kind: 'build', isDefault: true },
        dependsOn: ['Clean', 'Compile TypeScript', 'Bundle Assets'],
        dependsOrder: 'sequence'
      }
    ];
  }
  
  static createTestSuite(): TaskDefinitionConfig[] {
    return [
      {
        type: 'shell',
        label: 'Unit Tests',
        command: 'npm',
        args: ['run', 'test:unit'],
        group: 'test',
        problemMatcher: '$jest'
      },
      {
        type: 'shell',
        label: 'Integration Tests',
        command: 'npm',
        args: ['run', 'test:integration'],
        group: 'test',
        dependsOn: 'Unit Tests',
        problemMatcher: '$jest'
      },
      {
        type: 'shell',
        label: 'E2E Tests',
        command: 'npm',
        args: ['run', 'test:e2e'],
        group: 'test',
        dependsOn: 'Integration Tests'
      },
      {
        type: 'shell',
        label: 'All Tests',
        command: 'echo',
        args: ['All tests completed'],
        group: { kind: 'test', isDefault: true },
        dependsOn: ['Unit Tests', 'Integration Tests', 'E2E Tests']
      }
    ];
  }
}

// 2. 环境特定任务
class EnvironmentTasks {
  static createEnvironmentSpecificTasks(): TaskDefinitionConfig[] {
    return [
      {
        type: 'shell',
        label: 'Build (Development)',
        command: 'npm',
        args: ['run', 'build:dev'],
        group: 'build',
        options: {
          env: {
            NODE_ENV: 'development'
          }
        }
      },
      {
        type: 'shell',
        label: 'Build (Production)',
        command: 'npm',
        args: ['run', 'build:prod'],
        group: 'build',
        options: {
          env: {
            NODE_ENV: 'production'
          }
        }
      },
      {
        type: 'shell',
        label: 'Deploy (Staging)',
        command: 'npm',
        args: ['run', 'deploy:staging'],
        dependsOn: 'Build (Development)'
      },
      {
        type: 'shell',
        label: 'Deploy (Production)',
        command: 'npm',
        args: ['run', 'deploy:prod'],
        dependsOn: 'Build (Production)'
      }
    ];
  }
}

错误处理和调试

typescript
// 任务错误处理
class TaskErrorHandler {
  static setupErrorHandling(): void {
    tasks.onDidEndTask(event => {
      if (event.execution.task.group === TaskGroup.Build) {
        this.handleBuildTaskEnd(event);
      } else if (event.execution.task.group === TaskGroup.Test) {
        this.handleTestTaskEnd(event);
      }
    });
  }
  
  private static handleBuildTaskEnd(event: TaskEndEvent): void {
    // 检查构建任务的退出代码
    tasks.onDidEndTaskProcess(processEvent => {
      if (processEvent.execution === event.execution && processEvent.exitCode !== 0) {
        window.showErrorMessage(
          `Build failed: ${event.execution.task.name}`,
          'Show Problems',
          'Show Terminal'
        ).then(action => {
          if (action === 'Show Problems') {
            commands.executeCommand('workbench.panel.markers.view.focus');
          } else if (action === 'Show Terminal') {
            commands.executeCommand('workbench.panel.terminal.focus');
          }
        });
      }
    });
  }
  
  private static handleTestTaskEnd(event: TaskEndEvent): void {
    // 处理测试任务结果
    tasks.onDidEndTaskProcess(processEvent => {
      if (processEvent.execution === event.execution) {
        if (processEvent.exitCode === 0) {
          window.showInformationMessage('All tests passed! ✅');
        } else {
          window.showErrorMessage(
            'Some tests failed ❌',
            'Show Test Results'
          ).then(action => {
            if (action === 'Show Test Results') {
              commands.executeCommand('workbench.view.testing.focus');
            }
          });
        }
      }
    });
  }
}

相关 API

示例项目

查看 任务 API 示例 了解完整的实现示例。

您的终极 AI 驱动 IDE 学习指南