Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>AI生码率统计插件New to Visual Studio Code? Get it now.
AI生码率统计插件

AI生码率统计插件

heao

|
2 installs
| (0) | Free
实时统计AI vs 人工代码占比
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

AI代码统计插件 - 完整技术文档 v1.0.0

📋 项目概述

AI代码统计插件是一个功能强大的VSCode扩展,通过智能Git作者切换和精确diff算法,实时统计AI生成代码与人工编写代码的占比。插件采用最后修改者原则,只统计未提交的代码修改,提供准确的代码贡献度分析。

🎯 核心价值

  • 代码审查依据:精确区分AI与人工代码,为代码审查提供数据支撑
  • 开发效率量化:实时量化AI工具对开发效率的实际提升
  • 团队协作透明:清晰展示不同开发者和AI工具的代码贡献
  • 质量分析基础:为AI生成代码vs人工代码的质量分析提供数据基础
  • 开发习惯洞察:通过详细日志了解AI辅助编程的使用模式

🚀 功能特性

✨ 实时监听与统计

  • 文档变化监听:基于VSCode文档变化事件的实时监听
  • Git作者检测:自动获取当前Git作者,智能区分AI与人工身份
  • 精确Diff算法:采用Myers编辑距离算法,精确计算代码变化
  • 行级追踪:精确到行的代码归属和修改历史跟踪

🌐 网络请求功能(新增)

  • 仓库信息获取:自动获取Git远程仓库地址和解析仓库组名、仓库名
  • API接口上报:支持将仓库信息和统计数据上报到指定API接口
  • 智能地址解析:支持HTTPS、SSH、阿里内部GitLab等多种Git地址格式
  • 配置化管理:通过VSCode设置配置API接口地址,灵活可控

🧠 核心算法特性

  • 最后修改者原则:每行代码归属于最后修改它的人
  • 智能还原检测:代码还原到Git HEAD状态时自动移除修改标记
  • 净贡献计算:正确处理删除操作,计算真实的代码贡献度
  • 移动检测算法:识别代码行移动和重构,避免错误统计

💾 数据管理

  • 工作区隔离:不同工作区的统计数据完全独立
  • 跨会话持久化:插件重启后自动恢复统计状态
  • 缓存优化:Git操作缓存和防抖机制,提升性能
  • 数据完整性验证:自动验证和清理无效数据

🔧 智能Husky检测与安装

插件现在支持智能检测项目的husky状态,并提供用户友好的安装选项:

检测场景

  1. 非Node.js项目 (无package.json)

    • 询问是否直接设置Git钩子
    • 提供"是"、"否"、"不再询问"选项
  2. Node.js项目未安装husky

    • 自动检测包管理器(npm/yarn/pnpm)
    • 询问是否安装husky并设置钩子
    • 提供"是"、"否"、"总是自动安装"、"不再询问"选项
  3. 已安装husky的项目

    • 显示当前husky版本
    • 询问是否设置AI代码统计钩子
    • 提供"是"、"否"、"不再询问"选项

配置选项

{
  "aiCodeStats.autoSetupGitHooks": true,     // 是否启用自动设置Git钩子
  "aiCodeStats.autoInstallHusky": false,    // 是否自动安装husky而不询问
  "aiCodeStats.showDetailedInstallLogs": true // 是否显示详细的安装日志
}

📊 实时统计功能

  • 状态栏显示:实时显示当前AI生码率
  • 文件级统计:每个文件的AI vs 人工代码比例
  • 项目级汇总:整个项目的代码统计信息

🔄 Git集成功能

  • commit消息增强:自动在commit消息中添加统计信息
  • 作者智能切换:AI编码时自动切换到AI作者
  • 状态栏重置:commit后自动重置统计信息

🎮 操作检测

  • 粘贴检测:Ctrl+V粘贴操作检测
  • 退格检测:Backspace删除操作检测
  • 输入检测:键盘输入实时检测
  • 文件切换:自动检测文件切换并初始化统计

🎛️ 实时监听与拦截系统

核心拦截机制

插件通过拦截VSCode的原始操作命令,实现对人工编辑行为的精确检测:

拦截的关键操作

操作类型 拦截命令 检测目的 处理逻辑
键盘输入 type 检测人工打字 先切换到人工作者,再执行输入
粘贴操作 editor.action.clipboardPasteAction 检测剪贴板粘贴 先切换到人工作者,再执行粘贴
回车换行 editor.action.insertLineAfter 检测换行操作 先切换到人工作者,再插入换行
删除操作 deleteLeft, deleteRight 检测删除字符 先切换到人工作者,再执行删除
文件切换 onDidChangeActiveTextEditor 检测文件焦点 更新编辑上下文状态

人工操作检测算法

// 人工编辑检测的核心逻辑
interface EditingContext {
    isKeyboardActive: boolean;    // 键盘活动状态
    cursorInFile: boolean;        // 光标在文件内
    lastActivity: number;         // 最后活动时间
    preparingEdit: boolean;       // 准备编辑状态
}

// 检测条件:同时满足以下三个条件 = 人工操作
const isManualEdit = context.cursorInFile && 
                    context.isKeyboardActive && 
                    !context.preparingEdit;

防抖机制

为避免重复拦截,实现了50ms防抖:

function shouldSkipCommand(commandName: string, fileName: string): boolean {
    const key = `${commandName}:${fileName}`;
    const now = Date.now();
    const lastTime = commandDebounce.get(key) || 0;
    
    if (now - lastTime < 50) { // 50ms防抖
        return true;
    }
    
    commandDebounce.set(key, now);
    return false;
}

实时切换机制

自动作者切换逻辑

// 检测到人工操作时的处理流程
async function handleManualEditingIntent(fileName: string): Promise<void> {
    const manualAuthor = getManualGitAuthor();
    
    if (!manualAuthor) return;
    
    // 1. 强制获取最新Git作者
    clearGitCache(fileName);
    const currentAuthor = await getCurrentGitAuthor(fileName);
    
    // 2. 如果不是手动作者,立即切换
    if (currentAuthor !== manualAuthor) {
        const success = await switchGitAuthor(fileName, manualAuthor);
        if (success) {
            outputChannel.appendLine(`✅ 检测到人工操作,已切换到: ${manualAuthor}`);
        }
    }
}

事件监听架构

┌─────────────────────────────────────────────────────────────┐
│                    VSCode原始事件                            │
│  type │ paste │ deleteLeft │ deleteRight │ insertLineAfter   │
└─────────────────────┬───────────────────────────────────────┘
                      │ 拦截
┌─────────────────────▼───────────────────────────────────────┐
│                  拦截处理层                                  │
│  • 防抖检查 • 人工检测 • Git作者切换 • 命令转发             │
└─────────────────────┬───────────────────────────────────────┘
                      │ 处理完成
┌─────────────────────▼───────────────────────────────────────┐
│                  原始命令执行                                │
│  手动执行原始操作逻辑,确保编辑正常进行                      │
└─────────────────────────────────────────────────────────────┘

🔬 技术架构

核心数据结构

// 行状态定义
interface LineState {
    content: string;        // 行内容
    author: string;         // 作者
    isModified: boolean;    // 是否被修改
    lastModified?: number;  // 最后修改时间
}

// 文件状态定义
interface FileState {
    originalContent: string;                    // Git HEAD的原始内容
    currentLineStates: Map<number, LineState>;  // 当前行状态映射
    lastKnownContent: string;                   // 最后已知内容
    lastGitCommitHash: string;                  // 最后Git提交哈希
    lastModified: number;                       // 最后修改时间
    isProcessing: boolean;                      // 是否正在处理中
}

// Diff变化类型
interface DiffChange {
    type: 'added' | 'deleted' | 'modified' | 'unchanged';
    originalLine?: number;    // 原始行号
    currentLine?: number;     // 当前行号
    content: string;          // 行内容
}

系统架构图

┌─────────────────────────────────────────────────────────────┐
│                    VSCode 扩展入口                          │
└─────────────────────┬───────────────────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────────────────┐
│                  事件监听层                                  │
│  • 文档变化监听 • 编辑上下文检测 • 防抖处理                  │
└─────────────────────┬───────────────────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────────────────┐
│                  Git集成层                                   │
│  • 作者检测 • 原始内容获取 • 缓存管理 • 状态验证            │
└─────────────────────┬───────────────────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────────────────┐
│                 核心算法层                                   │
│  • Myers Diff算法 • 行状态管理 • 智能归属 • 边界检测       │
└─────────────────────┬───────────────────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────────────────┐
│                  数据持久化层                                │
│  • 工作区隔离 • 状态保存 • 数据恢复 • 完整性验证            │
└─────────────────────┬───────────────────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────────────────┐
│                   UI展示层                                   │
│  • 状态栏显示 • 详细报告 • 实时日志 • 命令面板             │
└─────────────────────────────────────────────────────────────┘

🔧 精确Diff算法详解

Myers编辑距离算法

插件采用Myers算法计算两个版本之间的最小编辑距离,这是Git和大多数版本控制系统使用的核心算法。

算法复杂度

  • 时间复杂度:O(ND),其中N为文件行数,D为编辑距离
  • 空间复杂度:O(N)
  • 最优性:保证找到最小编辑距离的最优路径

核心实现逻辑

function computeAccurateDiff(originalLines: string[], currentLines: string[]): DiffChange[] {
    const m = originalLines.length;
    const n = currentLines.length;
    const MAX = m + n;
    
    // Myers算法的核心数据结构
    const v = new Array(2 * MAX + 1).fill(-1);
    const trace: number[][] = [];
    
    // 前向搜索找到最短编辑路径
    for (let d = 0; d <= MAX; d++) {
        const currentV = [...v];
        trace.push(currentV);
        
        for (let k = -d; k <= d; k += 2) {
            let x: number;
            
            if (k === -d || (k !== d && v[k - 1 + MAX] < v[k + 1 + MAX])) {
                x = v[k + 1 + MAX];
            } else {
                x = v[k - 1 + MAX] + 1;
            }
            
            let y = x - k;
            
            // 处理相同行的情况
            while (x < m && y < n && originalLines[x] === currentLines[y]) {
                x++;
                y++;
            }
            
            v[k + MAX] = x;
            
            if (x >= m && y >= n) {
                return backtrackDiff(originalLines, currentLines, trace, x, y, d);
            }
        }
    }
    
    return [];
}

智能行匹配算法

为了处理代码移动和重构,插件实现了智能行匹配算法:

function findPreviousLineState(fileState: FileState, content: string, preferredLineNum: number): LineState | undefined {
    // 1. 优先匹配相同位置的行
    const exactMatch = fileState.currentLineStates.get(preferredLineNum);
    if (exactMatch && exactMatch.content === content) {
        return exactMatch;
    }
    
    // 2. 在附近行中查找相同内容
    const nearbyRange = 3;
    for (let i = 1; i <= nearbyRange; i++) {
        const above = fileState.currentLineStates.get(preferredLineNum - i);
        const below = fileState.currentLineStates.get(preferredLineNum + i);
        
        if (above && above.content === content) return above;
        if (below && below.content === content) return below;
    }
    
    // 3. 全文搜索相同内容
    for (const [lineNum, lineState] of fileState.currentLineStates) {
        if (lineState.content === content) {
            return lineState;
        }
    }
    
    return undefined;
}

还原检测机制

三重比较算法确保准确检测代码还原:

// 还原检测:当前内容 vs 上次内容 vs Git HEAD原始内容
function detectReversion(current: string, lastKnown: string, original: string): boolean {
    return current === original && lastKnown !== original;
}

🎯 极端边界情况处理

场景分类与处理策略

1. 基础修改删除场景

场景 描述 处理逻辑 期望结果
场景1 AI添加1行,人工删除1行 删除不计入统计,只看最终状态 0% AI,0% 人工
场景2 AI添加1行,人工添加1行,AI删除人工的1行 最终AI有1行,人工0行 100% AI,0% 人工
场景3 修改后完全还原到原始状态 检测到还原,清除所有标记 0% AI,0% 人工

2. 复杂编辑场景

场景 描述 核心算法 处理结果
场景4 批量删除操作 净贡献计算:只统计现存修改行 AI 3行,人工5行,总共8行
场景5 复制粘贴10行重复内容 不进行重复检测,按实际行数统计 AI贡献10行
场景6 格式化:1行变2行 格式化算正常代码贡献 AI贡献2行
场景7 重构:函数内容变化 基于diff算法识别实际修改行 AI修改1行

3. 操作撤销场景

场景 描述 检测机制 最终统计
场景8 撤销重做操作 监听最终状态变化 按最终结果统计
场景11 覆盖修改同一行 最后修改者原则 归属最后修改者
场景12 部分还原到原始状态 三重比较检测 还原行不算修改

4. 特殊编辑场景

场景 描述 算法处理 统计规则
场景23 回车换行插入空行 行级diff算法 算1行新增
场景24 删除换行合并两行 Myers算法识别 算1行修改
场景25 空行处理 空行算代码行 计入统计
场景26 自动格式化操作 触发者归属 算触发者贡献

5. Git状态变化场景

场景 描述 检测机制 处理策略
Git Stash 代码被暂存 监听Git状态变化 重置统计为0
Git Reset 硬重置到HEAD 检测commit hash变化 重新初始化
Git Pull 拉取远程更新 比较原始内容变化 只统计新修改

边界情况算法实现

// 场景检测与处理
async function handleEdgeCase(fileName: string, document: vscode.TextDocument): Promise<void> {
    const fileState = fileStates.get(fileName);
    if (!fileState) return;
    
    const currentContent = document.getText();
    const originalContent = fileState.originalContent;
    const lastKnownContent = fileState.lastKnownContent;
    
    // 1. 检测完全还原场景
    if (currentContent === originalContent) {
        if (lastKnownContent !== originalContent) {
            outputChannel.appendLine(`🔄 文件 ${fileName} 已还原到原始状态`);
            // 清除所有修改标记
            fileState.currentLineStates.clear();
            fileState.lastKnownContent = currentContent;
            return;
        }
    }
    
    // 2. 检测Git状态变化
    const currentGitHash = await getGitCommitHash(fileName);
    if (currentGitHash !== fileState.lastGitCommitHash) {
        outputChannel.appendLine(`🔄 检测到Git状态变化: ${fileName}`);
        await reinitializeFileState(fileName, document);
        return;
    }
    
    // 3. 处理正常diff场景
    await processNormalDiff(fileName, document);
}

📊 统计算法设计

净贡献计算公式

净贡献 = 新增行数 + 修改行数 - 被删除行数

占比计算算法

function calculatePercentages(): { ai: number, human: number } {
    let totalLines = 0;
    let aiLines = 0;
    
    const aiAuthors = getAIAuthors();
    
    // 统计所有文件的净贡献
    for (const [fileName, fileState] of fileStates) {
        for (const [lineNum, lineState] of fileState.currentLineStates) {
            if (lineState.isModified) {
                totalLines++;
                if (aiAuthors.has(lineState.author)) {
                    aiLines++;
                }
            }
        }
    }
    
    if (totalLines === 0) {
        return { ai: 0, human: 0 };
    }
    
    const aiPercentage = (aiLines / totalLines) * 100;
    const humanPercentage = 100 - aiPercentage;
    
    return { 
        ai: Math.round(aiPercentage * 10) / 10,
        human: Math.round(humanPercentage * 10) / 10
    };
}

删除处理逻辑

// 删除操作不增加删除者的贡献,只移除被删除行的统计
function handleDeletedLines(deletedLines: DiffChange[], fileName: string): void {
    const fileState = fileStates.get(fileName);
    if (!fileState) return;
    
    for (const change of deletedLines) {
        if (change.type === 'deleted' && change.originalLine) {
            // 从统计中移除被删除的行
            fileState.currentLineStates.delete(change.originalLine);
            
            outputChannel.appendLine(
                `🗑️ 删除了第${change.originalLine}行: "${change.content.substring(0, 50)}..."`
            );
        }
    }
}

🔧 V5性能优化设计

多层级缓存系统

L1:函数级缓存(withCache装饰器)

interface CacheEntry<T> {
    value: T;
    timestamp: number;
    ttl: number;        // 生存时间(默认30秒)
}

// 高阶函数包装,为任何异步函数添加缓存
const getCurrentGitAuthor = withCache(_getCurrentGitAuthor, getCacheTimeout());
const getGitOriginalContent = withCache(_getGitOriginalContent, getCacheTimeout());

L2:Git操作缓存

// Git命令结果缓存,避免重复执行相同操作
let gitCache = new Map<string, CacheEntry<any>>();

// 自动过期清理(每分钟执行)
function clearExpiredCache(): void {
    const now = Date.now();
    let cleared = 0;
    
    for (const [key, entry] of gitCache.entries()) {
        if (now - entry.timestamp > entry.ttl) {
            gitCache.delete(key);
            cleared++;
        }
    }
    
    outputChannel.appendLine(`🧹 清理过期缓存: ${cleared}个`);
}

L3:文档变化防抖

// 100ms防抖处理,批量处理文档变化
let documentChangeTimer: NodeJS.Timeout | undefined;
let pendingChanges = new Map<string, vscode.TextDocument>();

function debounceDocumentChange(document: vscode.TextDocument): void {
    const fileName = document.fileName;
    
    if (documentChangeTimer) {
        clearTimeout(documentChangeTimer);
    }
    
    pendingChanges.set(fileName, document);
    
    documentChangeTimer = setTimeout(async () => {
        // 批量处理所有待处理的文档变化
        for (const [fileName, doc] of pendingChanges) {
            await processDocumentChangeV5(fileName, doc);
        }
        pendingChanges.clear();
        documentChangeTimer = undefined;
    }, 100);
}

并发控制机制

Gate函数(防重复执行)

// 同一参数的异步操作只执行一次,其他调用等待结果
function gateAsync<T extends (...args: any[]) => Promise<any>>(fn: T): T {
    return ((...args: any[]) => {
        const key = JSON.stringify(args);
        
        // 如果已有相同操作在执行,直接返回Promise
        if (pendingGitOperations.has(key)) {
            return pendingGitOperations.get(key)!;
        }
        
        const promise = fn(...args);
        pendingGitOperations.set(key, promise);
        
        // 操作完成后清理
        promise.finally(() => pendingGitOperations.delete(key));
        
        return promise;
    }) as T;
}

操作队列管理

// 防止同时处理同一文件的多个操作
let processingQueue = new Set<string>();

async function processDocumentChangeV5(fileName: string, document: vscode.TextDocument): Promise<number[]> {
    // 防止重复处理
    if (processingQueue.has(fileName)) {
        return [];
    }
    
    processingQueue.add(fileName);
    
    try {
        // 处理逻辑...
        return changedLines;
    } finally {
        processingQueue.delete(fileName);
    }
}

内存优化策略

文件大小限制

function getMaxFileSize(): number {
    return getConfiguration().get<number>('maxFileSize', 5000);
}

// 跳过大文件处理,避免内存溢出
if (document.lineCount > getMaxFileSize()) {
    outputChannel.appendLine(`⏭️ 跳过大文件 (${document.lineCount}行): ${fileName}`);
    return;
}

定期清理机制

// 每分钟自动清理过期缓存
const cacheCleanupInterval = setInterval(clearExpiredCache, 60000);

// 插件停用时清理所有资源
export function deactivate() {
    clearInterval(cacheCleanupInterval);
    gitCache.clear();
    fileStates.clear();
    editingContexts.clear();
}

性能监控

操作耗时统计

async function processDocumentChangeV5(fileName: string, document: vscode.TextDocument): Promise<number[]> {
    const startTime = Date.now();
    
    try {
        // 处理逻辑...
        return changedLines;
    } finally {
        const duration = Date.now() - startTime;
        if (duration > 100) {
            outputChannel.appendLine(`⚠️ 处理耗时较长: ${fileName} - ${duration}ms`);
        }
    }
}

---

## ⚙️ 详细配置指南

### 必要配置检查清单

#### ✅ 第一步:AI作者列表配置
```json
{
  "aiCodeStats.aiAuthors": [
    "ai111",        // 推荐:统一的AI标识
    "AI", 
    "ChatGPT", 
    "Claude", 
    "Copilot",
    "cursor-ai",    // Cursor的AI助手
    "ai"
  ]
}

重要提醒:

  • 确保你在prompt中使用的AI作者名称在此列表中
  • 建议团队统一使用ai111作为标准AI标识
  • 可以随时添加新的AI工具名称

✅ 第二步:手动作者配置

{
  "aiCodeStats.manualGitAuthor": "张三"
}

配置说明:

  • 设置为你的真实Git用户名
  • 插件检测到人工操作时会自动切换到此作者
  • 留空则不进行自动切换

✅ 第三步:验证配置生效

  1. 打开输出面板:查看 → 输出 → AI Code Stats V5
  2. 查看状态栏显示当前Git作者
  3. 进行一次编辑操作,观察日志输出

✅ 第四步:配置网络请求功能(可选)

{
  "aiCodeStats.apiUrl": "https://your-api-endpoint.com/api/repository"
}

配置说明:

  • 设置你的API接口地址用于接收仓库信息
  • 支持HTTPS和HTTP协议
  • 留空或使用默认值则不启用网络请求功能

🌐 网络请求功能详解

支持的Git地址格式:

  • HTTPS格式:https://github.com/user/repo.git
  • SSH格式:git@github.com:user/repo.git
  • 阿里内部:http://gitlab.alibaba-inc.com/group/repo.git

发送的数据格式:

{
  "group": "message-social-front",
  "repo": "ai-code-plugin",
  "timestamp": "2024-01-01T12:00:00.000Z",
  "currentAuthor": "ai-鹤傲",
  "fileCount": 15,
  "pluginVersion": "1.0.0"
}

使用方法:

  1. 使用命令面板 (Ctrl+Shift+P)
  2. 搜索并执行 AI Code Stats: 发送仓库信息
  3. 插件会自动获取Git仓库信息并发送到配置的API接口

错误处理:

  • 如果未配置API地址,会提示配置
  • 如果不是Git仓库,会提示错误
  • 网络请求失败会显示详细错误信息

配置验证方法

快速测试流程

  1. 创建测试文件:新建一个.js文件
  2. AI生成代码:使用AI助手生成几行代码
  3. 检查状态栏:应显示AI占比
  4. 人工编辑:手动添加一行代码
  5. 验证切换:检查日志是否显示作者切换

故障排查

# 检查当前Git配置
git config user.name
git config --global user.name

# 验证Git仓库状态
git status
git log --oneline -n 5

🔍 完整配置选项

{
  "aiCodeStats.aiAuthors": {
    "type": "array",
    "default": ["ai111", "AI", "ChatGPT", "Claude", "Copilot", "ai"],
    "description": "AI作者名称列表,用于识别AI生成的代码"
  },
  "aiCodeStats.enabled": {
    "type": "boolean",
    "default": true,
    "description": "是否启用AI代码统计功能"
  },
  "aiCodeStats.autoExport": {
    "type": "boolean",
    "default": false,
    "description": "是否自动导出统计数据到项目根目录"
  },
  "aiCodeStats.preCommitHook": {
    "type": "boolean",
    "default": true,
    "description": "是否启用pre-commit hook,将统计信息添加到commit消息"
  },
  "aiCodeStats.manualGitAuthor": {
    "type": "string",
    "default": "",
    "description": "手动编辑时的Git作者名称。当检测到手动编辑时,会自动切换到此作者"
  },
  "aiCodeStats.maxFileSize": {
    "type": "number",
    "default": 5000,
    "description": "监控文件的最大行数限制,超过此限制的文件将被跳过"
  },
  "aiCodeStats.cacheTimeout": {
    "type": "number",
    "default": 30000,
    "description": "Git操作缓存超时时间(毫秒),用于优化性能"
  },
  "aiCodeStats.apiUrl": {
    "type": "string",
    "default": "https://your-api-endpoint.com/api/repository",
    "description": "仓库信息上报接口地址,用于网络请求功能"
  }
}

命令系统

命令 功能 说明
Toggle AI Code Stats 启用/禁用插件 可以临时关闭统计功能
Show AI Code Report 显示详细报告 展示完整的统计数据和分析
Reset AI Code Stats 重置统计 清空当前工作区的所有统计数据
Export AI Code Stats 导出数据 将统计数据导出为JSON格式
Send Repository Info 发送仓库信息 获取Git仓库信息并发送到配置的API接口
Verify Git Status Consistency 验证一致性 检查Git状态与插件状态的一致性
Clear Memory Cache 清空缓存 清除所有内存缓存,强制重新计算

🚀 完整使用指南

安装和配置流程

步骤1:插件安装

  1. VSCode安装:

    # 下载项目中的 .vsix 文件
    code --install-extension ai-code-stats-x.x.x.vsix
    
  2. 导入到Cursor:

    • 打开Cursor
    • 进入 Settings → General → Import from VSCode
    • 选择导入扩展和配置

步骤2:配置AI全局Prompt

在Cursor的User Rules中添加以下prompt模板:

# AI代码生成时自动切换Git作者身份
每当你要生成代码时,请先执行以下命令切换Git作者身份:

```bash
git config user.name "ai111"

[此处为你的具体AI使用规则和要求]

重要提醒:

  • 生成代码前必须先切换Git作者为ai111
  • 这样可以准确统计AI生成的代码占比
  • 请确保每次都执行此命令

### 完整工作流程

#### AI生成代码链路
1. **用户发起AI请求** → 触发全局prompt
2. **AI自动执行** `git config user.name "ai111"`
3. **AI生成代码** → 插件检测到代码变化
4. **插件识别AI作者** → 统计AI贡献
5. **状态栏实时更新** → 显示AI占比

#### 人工编辑代码链路
1. **用户开始编辑** → 插件检测到人工操作
2. **插件自动切换** → `git config user.name "张三"`
3. **人工编写代码** → 插件统计人工贡献
4. **状态栏实时更新** → 显示人工占比

### ⚠️ 重要注意事项
- **避免并发编辑**:AI生成代码过程中,人工最好不要同时修改代码
- **配置手动作者**:在插件设置中配置`manualGitAuthor`为你的Git用户名
- **AI作者列表可配置**:在`aiCodeStats.aiAuthors`中添加你使用的AI工具名称
- **Git仓库要求**:项目必须初始化Git仓库(`git init`即可,无需远程仓库)

### Git作者切换工作流

```bash
# 使用AI工具时
git config user.name "ai111"

# 人工编写代码时
git config user.name "张三"

# 查看当前作者
git config user.name

高级使用技巧

1. 自动化Git Hooks

# 安装husky
npm install husky --save-dev

# 设置pre-commit hook
npx husky add .husky/pre-commit "code --command aiCodeStats.export"

2. 团队协作配置

// .vscode/settings.json
{
  "aiCodeStats.aiAuthors": [
    "ai111",
    "team-ai-tool",
    "copilot-team"
  ],
  "aiCodeStats.autoExport": true,
  "aiCodeStats.preCommitHook": true
}

3. CI/CD集成

# .github/workflows/ai-stats.yml
name: AI Code Statistics
on: [push, pull_request]
jobs:
  ai-stats:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Analyze AI Code Stats
        run: |
          if [ -f .ai-code-stats.json ]; then
            echo "AI Code Statistics:"
            cat .ai-code-stats.json | jq '.summary'
          fi

💾 数据存储与状态管理

存储机制详解

数据存储位置

// VSCode GlobalState存储
const workspaceKey = `aiCodeStats.fileStates.${workspaceRoot}`;
await context.globalState.update(workspaceKey, data);

// 存储格式
interface StoredData {
    fileStates: Map<string, FileState>;    // 文件状态映射
    lastSaved: number;                     // 最后保存时间
    version: string;                       // 数据版本
}

存储内容

  • 只存储状态信息:行号、作者、修改标记等元数据
  • 不存储代码内容:确保代码安全,不会泄露
  • 工作区隔离:不同项目的数据完全分离
  • 无跨设备同步:数据存储在本地VSCode配置中

状态监控方式

1. 状态栏实时显示

$(person) 张三 | AI:65.3% 人工:34.7% (124行)

2. 输出面板详细日志

打开方式:查看 → 输出 → 选择 AI Code Stats V5

关键日志示例:

📋 V5初始化文件: main.ts
   当前作者: ai111
   发现15行已修改,等待编辑时归属
⌨️ 检测到文件修改输入: "console.log"
✅ 检测到人工操作,已切换到: 张三
🔍 增量diff分析: 3个变化
➕ 检测到第25行新增
📊 当前统计: AI:65.3% 人工:34.7% (124行)

Git状态处理策略

初始化时Git状态不Clean的处理

现有机制:

// V5处理逻辑:标记为已修改但不归属
if (isAlreadyModified) {
    lineStates.set(lineNum, {
        content: currentLine,
        author: '',           // 不归属给任何人
        isModified: true,     // 标记为已修改
        lastModified: Date.now()
    });
}

建议改进方案:

  1. 检测到未提交修改时弹出提示:

    "检测到当前文件有未提交的修改,插件将从下一次编辑开始统计。
    建议先提交当前修改或使用'Reset AI Code Stats'重新开始统计。"
    
  2. 提供快速操作选项:

    • 继续使用 - 采用现有逻辑,不归属已有修改
    • 重置统计 - 清空所有统计,从0开始
    • 归属当前作者 - 将所有未提交修改归属给当前Git作者

🔧 Git操作详解

插件执行的Git命令列表

Git命令 用途 执行时机 错误处理
git config user.name 获取当前作者 每次文件变化 回退到全局配置
git config --global user.name 获取全局作者 本地配置失败时 设为'Unknown'
git config user.name "author" 切换Git作者 检测到人工编辑 静默失败,记录日志
git show HEAD:"file" 获取原始内容 文件初始化时 当作新文件处理

Git仓库要求

最低要求

  • ✅ 执行过 git init
  • ✅ 文件被Git跟踪(至少add过一次)
  • ❌ 不需要远程仓库
  • ❌ 不需要提交历史

推荐状态

  • 🎯 工作区相对干净(便于准确统计)
  • 🎯 定期提交代码(重置统计基线)

🐛 故障排除

常见问题诊断

问题1:统计数据不准确

症状:显示的AI/人工占比与实际情况不符 排查步骤:

  1. 检查输出面板的详细日志
  2. 验证Git作者配置:git config user.name
  3. 确认文件在Git仓库中:git status
  4. 使用Verify Git Status Consistency命令检查

问题2:插件性能问题

症状:VSCode响应缓慢,插件占用资源过高 解决方案:

  1. 调整maxFileSize配置,跳过大文件
  2. 增加cacheTimeout时间,减少Git操作频率
  3. 使用Clear Memory Cache清空缓存

问题3:数据持久化失败

症状:重启VSCode后统计数据丢失 排查步骤:

  1. 检查VSCode权限,确保可以写入globalState
  2. 查看输出面板的保存/加载日志
  3. 验证工作区路径是否正确

调试模式

启用详细日志输出:

// 在输出面板查看详细日志
outputChannel.show();

// 关键日志示例
outputChannel.appendLine(`📂 初始化文件: ${fileName}`);
outputChannel.appendLine(`🔄 检测到${changes.length}行变化`);
outputChannel.appendLine(`📊 当前统计: AI:${aiPercentage}% 人工:${humanPercentage}%`);

📈 数据导出格式

JSON导出结构

{
  "timestamp": "2024-01-01T00:00:00.000Z",
  "workspaceRoot": "/path/to/project",
  "totalModifiedLines": 150,
  "totalFiles": 5,
  "summary": {
    "ai": 98,
    "human": 52,
    "aiPercentage": "65.33",
    "humanPercentage": "34.67"
  },
  "authors": {
    "ai111": {
      "lines": 98,
      "files": 3,
      "isAI": true,
      "percentage": "65.33"
    },
    "张三": {
      "lines": 52,
      "files": 4,
      "isAI": false,
      "percentage": "34.67"
    }
  },
  "fileDetails": {
    "src/main.ts": {
      "totalLines": 45,
      "authors": {
        "ai111": 30,
        "张三": 15
      }
    }
  }
}

🔬 技术深度分析

Myers算法的优势

  1. 最优性保证:保证找到最小编辑距离
  2. 性能优秀:对于大多数实际代码场景,性能表现良好
  3. 广泛应用:Git、SVN等版本控制系统的标准算法
  4. 稳定可靠:经过长期验证,算法稳定性高

拦截实现技术细节

命令拦截的完整实现

// 1. 键盘输入拦截
const typeCommandDisposable = vscode.commands.registerCommand('type', async (args) => {
    const editor = vscode.window.activeTextEditor;
    if (editor && isCodeFile(editor.document.fileName)) {
        const fileName = editor.document.fileName;
        
        // 防抖检查,避免重复处理
        if (shouldSkipCommand('type', fileName)) {
            return await vscode.commands.executeCommand('default:type', args);
        }
        
        // 检测是否会修改文件
        const text = args?.text || '';
        if (text && text.length > 0) {
            outputChannel.appendLine(`⌨️ 检测到文件修改输入: "${text}"`);
            
            // 先切换到人工作者,等待完成
            await handleManualEditingIntent(fileName);
        }
    }
    
    // 执行原始的type命令
    return await vscode.commands.executeCommand('default:type', args);
});

// 2. 粘贴操作拦截
const pasteCommandDisposable = vscode.commands.registerCommand('editor.action.clipboardPasteAction', async () => {
    const editor = vscode.window.activeTextEditor;
    if (editor && isCodeFile(editor.document.fileName)) {
        const fileName = editor.document.fileName;
        
        if (!shouldSkipCommand('paste', fileName)) {
            outputChannel.appendLine(`📋 检测到粘贴操作: ${path.basename(fileName)}`);
            await handleManualEditingIntent(fileName);
        }
    }
    
    // 手动执行粘贴逻辑
    const clipboardText = await vscode.env.clipboard.readText();
    if (clipboardText && editor) {
        await editor.edit(editBuilder => {
            const selection = editor.selection;
            editBuilder.replace(selection, clipboardText);
        });
    }
});

// 3. 删除操作拦截(支持左删除和右删除)
const deleteLeftDisposable = vscode.commands.registerCommand('deleteLeft', async () => {
    const editor = vscode.window.activeTextEditor;
    if (editor && isCodeFile(editor.document.fileName)) {
        const fileName = editor.document.fileName;
        
        if (!shouldSkipCommand('deleteLeft', fileName)) {
            outputChannel.appendLine(`⌫ 检测到删除操作: ${path.basename(fileName)}`);
            await handleManualEditingIntent(fileName);
        }
    }
    
    // 手动执行删除逻辑
    if (editor) {
        await editor.edit(editBuilder => {
            const selection = editor.selection;
            if (selection.isEmpty) {
                // 删除光标前一个字符或合并行
                const position = selection.active;
                if (position.character > 0) {
                    const deleteRange = new vscode.Range(
                        position.line, position.character - 1,
                        position.line, position.character
                    );
                    editBuilder.delete(deleteRange);
                } else if (position.line > 0) {
                    const prevLineEnd = editor.document.lineAt(position.line - 1).range.end;
                    editBuilder.delete(new vscode.Range(prevLineEnd, position));
                }
            } else {
                editBuilder.delete(selection);
            }
        });
    }
});

编辑上下文状态管理

// 编辑上下文状态跟踪
interface EditingContext {
    isKeyboardActive: boolean;    // 键盘是否活跃
    cursorInFile: boolean;        // 光标在文件内
    lastActivity: number;         // 最后活动时间戳
    preparingEdit: boolean;       // 是否正在准备编辑
}

// 状态更新和日志记录
function updateEditingContext(fileName: string, updates: Partial<EditingContext>): void {
    const context = getEditingContext(fileName);
    Object.assign(context, updates, { lastActivity: Date.now() });
    editingContexts.set(fileName, context);
    
    outputChannel.appendLine(
        `📝 更新编辑上下文: ${path.basename(fileName)} - ` +
        `光标:${context.cursorInFile}, 键盘:${context.isKeyboardActive}, 准备:${context.preparingEdit}`
    );
}

边界情况处理的哲学

插件采用**"最终状态导向"**的设计哲学:

  • 简单归属:每行代码归属于最后修改者
  • 忽略过程:不关注修改的中间过程,只看最终结果
  • 净贡献原则:删除操作不算贡献,只统计实际存在的修改
  • 工程实用性:在算法复杂度和实用性之间找到平衡
  • 实时响应:拦截操作确保Git作者切换在编辑前完成

性能优化策略

  1. 缓存层次化:

    • L1缓存:内存缓存(函数级)
    • L2缓存:操作缓存(Git命令级)
    • L3缓存:会话缓存(文件状态级)
  2. 并发控制:

    • Gate函数防止重复操作
    • 队列管理避免资源竞争
    • 防抖机制减少触发频率
  3. 内存管理:

    • 定期清理过期缓存
    • 限制文件大小避免内存溢出
    • 工作区隔离防止数据混合

🎯 最佳实践

团队使用建议

  1. 统一AI作者命名:团队统一使用如"ai111"的AI作者名称
  2. 及时切换身份:根据代码来源及时切换Git作者
  3. 定期导出数据:在重要里程碑导出统计数据留档
  4. 结合代码审查:将AI生成代码作为审查重点

个人使用技巧

  1. 养成切换习惯:使用AI工具前后及时切换Git作者
  2. 监控实时数据:通过状态栏随时了解AI使用情况
  3. 定期重置统计:项目阶段性重置避免数据累积
  4. 合理配置参数:根据团队需求调整插件配置

📊 版本演进历史

版本 主要特性 技术改进
v1.x 基础统计功能 简单行匹配算法
v2.x Git集成 添加Git diff支持
v3.x 智能检测 引入Myers算法
v4.x 性能优化 缓存系统和防抖
v5.x 完整边界处理 28种极端场景覆盖

🤝 贡献指南

开发环境搭建

# 克隆项目
git clone <repository-url>
cd ai-code-stats

# 安装依赖
npm install

# 编译TypeScript
npm run compile

# 监听文件变化
npm run watch

测试用例添加

// 添加新的边界情况测试
describe('Edge Case: New Scenario', () => {
    it('should handle specific edge case correctly', async () => {
        // 测试实现
    });
});

算法改进

如果发现新的边界情况或算法问题,请:

  1. 在test-extreme-cases.md中记录场景
  2. 添加对应的测试用例
  3. 修改核心算法逻辑
  4. 验证所有现有测试通过

💬 联系方式

  • 问题反馈:通过 GitHub Issues 提交
  • 功能建议:欢迎提交 Pull Request
  • 技术讨论:查看插件输出面板的详细日志

AI代码统计插件 - 让AI代码贡献度透明化,让开发过程数据化!

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2025 Microsoft