UNPKG

cc-code-status

Version:

Enhanced Claude Code launcher with statusline - supports multiple custom API configurations and code statistics

535 lines 20.8 kB
"use strict"; /** * 旧版 CLI 函数(向后兼容) * 包含 v1.x 版本的所有辅助函数 */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.setup = setup; exports.uninstall = uninstall; exports.setSyncEnabled = setSyncEnabled; exports.showSyncStatus = showSyncStatus; exports.manualSync = manualSync; exports.customSync = customSync; exports.handleExclude = handleExclude; exports.showWeekStats = showWeekStats; const fs = __importStar(require("fs")); const path = __importStar(require("path")); const os = __importStar(require("os")); const child_process_1 = require("child_process"); const index_1 = require("./index"); function setup() { console.log('🚀 设置 CC Code Status 插件...'); const claudeSettingsDir = path.join(os.homedir(), '.claude'); const claudeSettingsFile = path.join(claudeSettingsDir, 'settings.json'); if (!fs.existsSync(claudeSettingsDir)) { console.log('📁 创建 Claude 设置目录...'); fs.mkdirSync(claudeSettingsDir, { recursive: true }); } const commandPath = 'cc-code-status'; let settings = {}; if (fs.existsSync(claudeSettingsFile)) { console.log('📝 更新现有 settings.json...'); const backupFile = `${claudeSettingsFile}.backup`; fs.copyFileSync(claudeSettingsFile, backupFile); console.log(` 备份保存至: ${backupFile}`); try { const existingContent = fs.readFileSync(claudeSettingsFile, 'utf8'); settings = JSON.parse(existingContent); } catch (error) { console.error('⚠️ 读取现有设置出错,创建新设置...'); settings = {}; } } else { console.log('📝 创建新的 settings.json...'); } settings.statusLine = { type: 'command', command: commandPath }; fs.writeFileSync(claudeSettingsFile, JSON.stringify(settings, null, 2)); console.log('✅ 设置更新成功!'); console.log(''); console.log('🎉 CC Code Status 插件已配置完成!'); console.log(''); } function uninstall() { console.log('🗑️ 移除 CC Code Status 插件配置...'); const claudeSettingsFile = path.join(os.homedir(), '.claude', 'settings.json'); if (!fs.existsSync(claudeSettingsFile)) { console.log('⚠️ 未找到 Claude 设置文件。'); return; } try { const content = fs.readFileSync(claudeSettingsFile, 'utf8'); const settings = JSON.parse(content); if (settings.statusLine) { delete settings.statusLine; fs.writeFileSync(claudeSettingsFile, JSON.stringify(settings, null, 2)); console.log('✅ StatusLine 配置已从 Claude 设置中移除。'); } else { console.log('⚠️ 设置中未找到 statusLine 配置。'); } } catch (error) { console.error('❌ 更新设置时出错:', error); } } function setSyncEnabled(enabled) { const configDir = path.join(os.homedir(), '.cc-code-status'); const configFile = path.join(configDir, 'config.json'); if (!fs.existsSync(configDir)) { fs.mkdirSync(configDir, { recursive: true }); } let config = { apiUrl: 'http://10.40.0.70:8087/api/cloudcode-ai/batch-receive', syncInterval: 1800000, enabled: false }; if (fs.existsSync(configFile)) { try { const content = fs.readFileSync(configFile, 'utf8'); config = JSON.parse(content); } catch (error) { console.error('⚠️ 读取配置文件失败,使用默认配置'); } } config.enabled = enabled; try { fs.writeFileSync(configFile, JSON.stringify(config, null, 2)); console.log(''); if (enabled) { console.log('✅ 数据上报功能已启用'); console.log(''); console.log(`📡 API 地址: ${config.apiUrl}`); console.log(`⏱️ 同步间隔: ${config.syncInterval / 1000 / 60} 分钟`); } else { console.log('✅ 数据上报功能已禁用'); } console.log(''); console.log(`配置文件: ${configFile}`); console.log(''); } catch (error) { console.error('❌ 写入配置文件失败:', error); } } function showSyncStatus() { const configFile = path.join(os.homedir(), '.cc-code-status', 'config.json'); if (!fs.existsSync(configFile)) { console.log(''); console.log('⚠️ 配置文件不存在'); console.log(''); console.log('运行以下命令启用数据上报:'); console.log(' ccs sync-enable'); console.log(''); return; } try { const content = fs.readFileSync(configFile, 'utf8'); const config = JSON.parse(content); console.log(''); console.log('========================================'); console.log(' 数据上报状态'); console.log('========================================'); console.log(''); console.log(`状态: ${config.enabled ? '✅ 已启用' : '❌ 已禁用'}`); console.log(`API 地址: ${config.apiUrl || '(未配置)'}`); console.log(`同步间隔: ${(config.syncInterval || 1800000) / 1000 / 60} 分钟`); console.log(''); console.log(`配置文件: ${configFile}`); console.log(''); } catch (error) { console.error('❌ 读取配置失败:', error); } } async function manualSync() { const plugin = new index_1.StatusLinePlugin(); await index_1.StatusLinePlugin.manualSync(); } async function customSync() { const readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); console.log(''); console.log('========================================'); console.log(' 自定义数据上报'); console.log('========================================'); console.log(''); let username = 'Unknown'; try { username = (0, child_process_1.execSync)('git config user.name', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim(); } catch { // 忽略错误 } const askQuestion = (question) => { return new Promise((resolve) => { rl.question(question, (answer) => { resolve(answer.trim()); }); }); }; try { const configFile = path.join(os.homedir(), '.cc-code-status', 'config.json'); if (!fs.existsSync(configFile)) { console.log('❌ 配置文件不存在,请先运行: ccs sync-enable'); console.log(''); rl.close(); return; } const configContent = fs.readFileSync(configFile, 'utf8'); const config = JSON.parse(configContent); if (!config.enabled) { console.log('❌ 数据上报功能未启用'); console.log(''); console.log('请先运行以下命令启用数据上报:'); console.log(' ccs sync-enable'); console.log(''); rl.close(); return; } if (!config.apiUrl) { console.log('❌ API 地址未配置'); console.log(''); console.log(`请在配置文件中设置 apiUrl: ${configFile}`); console.log(''); rl.close(); return; } console.log(`当前用户: ${username}`); console.log(''); const roundsInput = await askQuestion('请输入对话轮次: '); const rounds = parseInt(roundsInput, 10); if (isNaN(rounds) || rounds < 0) { console.log(''); console.log('❌ 对话轮次必须是非负整数'); console.log(''); rl.close(); return; } const addedInput = await askQuestion('请输入新增代码行数: '); const codeAdded = parseInt(addedInput, 10); if (isNaN(codeAdded) || codeAdded < 0) { console.log(''); console.log('❌ 新增代码行数必须是非负整数'); console.log(''); rl.close(); return; } const deletedInput = await askQuestion('请输入删除代码行数: '); const codeDeleted = parseInt(deletedInput, 10); if (isNaN(codeDeleted) || codeDeleted < 0) { console.log(''); console.log('❌ 删除代码行数必须是非负整数'); console.log(''); rl.close(); return; } console.log(''); console.log('数据汇总:'); console.log(` 用户: ${username}`); console.log(` 对话轮次: ${rounds}`); console.log(` 新增代码: ${codeAdded} 行`); console.log(` 删除代码: ${codeDeleted} 行`); console.log(''); const confirm = await askQuestion('确认上报以上数据?(y/n): '); if (confirm.toLowerCase() !== 'y' && confirm.toLowerCase() !== 'yes') { console.log(''); console.log('❌ 已取消上报'); console.log(''); rl.close(); return; } const today = new Date(); const dateString = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`; const conversationDetail = { id: `custom-${Date.now()}`, userId: username, userName: username, conversationCount: rounds, adoptedLines: codeAdded + codeDeleted, codeAdded: codeAdded, codeDeleted: codeDeleted, messages: [], createDate: dateString, updatedAt: dateString }; const plugin = new index_1.StatusLinePlugin(); plugin.syncToBackend(config.apiUrl, [conversationDetail]); console.log(''); console.log('✅ 数据已提交上报'); console.log(''); rl.close(); } catch (error) { console.log(''); console.log('❌ 上报失败:', error); console.log(''); rl.close(); } } function handleExclude(subArgs) { const subCommand = subArgs[0]; const projectPath = subArgs[1]; if (subCommand === 'add' && projectPath) { index_1.StatusLinePlugin.addExcludedProject(projectPath); } else if (subCommand === 'remove' && projectPath) { index_1.StatusLinePlugin.removeExcludedProject(projectPath); } else if (subCommand === 'list') { index_1.StatusLinePlugin.listExcludedProjects(); } else { console.log(''); console.log('用法:'); console.log(' ccs exclude add <项目路径> 添加排除项目'); console.log(' ccs exclude remove <项目路径> 移除排除项目'); console.log(' ccs exclude list 列出排除项目'); console.log(''); } } function showWeekStats() { const { execSync } = require('child_process'); try { let username = 'Unknown'; try { username = execSync('git config user.name', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim(); } catch { // 忽略错误 } const today = new Date(); const dayOfWeek = today.getDay(); const daysToMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1; const weekStart = new Date(today); weekStart.setDate(today.getDate() - daysToMonday); weekStart.setHours(0, 0, 0, 0); const weekEnd = new Date(weekStart); weekEnd.setDate(weekStart.getDate() + 6); weekEnd.setHours(23, 59, 59, 999); const dailyStats = []; let totalConversations = 0; let totalRounds = 0; let totalAdded = 0; let totalDeleted = 0; const dayNames = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']; for (let i = 0; i < 7; i++) { const currentDay = new Date(weekStart); currentDay.setDate(weekStart.getDate() + i); const dayStart = new Date(currentDay); dayStart.setHours(0, 0, 0, 0); const dayEnd = new Date(currentDay); dayEnd.setHours(23, 59, 59, 999); const conversations = countConversations(dayStart, dayEnd); const rounds = countRounds(dayStart, dayEnd); const codeStats = countCodeChanges(dayStart, dayEnd); totalConversations += conversations; totalRounds += rounds; totalAdded += codeStats.added; totalDeleted += codeStats.deleted; dailyStats.push({ date: formatDate(currentDay), dayName: dayNames[currentDay.getDay()], conversations, rounds, codeAdded: codeStats.added, codeDeleted: codeStats.deleted }); } console.log(''); console.log('========================================'); console.log(` 本周统计 (${formatDate(weekStart)}${formatDate(weekEnd)})`); console.log('========================================'); console.log(''); console.log(`总计: ${totalConversations}次/${totalRounds}轮 | +${totalAdded}/-${totalDeleted} 行`); console.log(''); console.log('每日明细:'); console.log(''); for (const day of dailyStats) { const dateStr = `${day.dayName} (${day.date})`; const statsStr = `${day.conversations}次/${day.rounds}轮 | +${day.codeAdded}/-${day.codeDeleted} 行`; console.log(` ${dateStr.padEnd(20)} ${statsStr}`); } console.log(''); } catch (error) { console.error('❌ 统计失败:', error); } } // 辅助函数 function formatDate(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } function countConversations(dayStart, dayEnd) { try { const projectsDir = path.join(os.homedir(), '.claude', 'projects'); if (!fs.existsSync(projectsDir)) return 0; const sessionIds = new Set(); const projectDirs = fs.readdirSync(projectsDir); for (const dir of projectDirs) { const dirPath = path.join(projectsDir, dir); if (!fs.statSync(dirPath).isDirectory()) continue; const files = fs.readdirSync(dirPath).filter(f => f.endsWith('.jsonl') && !f.startsWith('agent-')); for (const file of files) { const filePath = path.join(dirPath, file); const content = fs.readFileSync(filePath, 'utf8'); const lines = content.trim().split('\n'); for (const line of lines) { try { const record = JSON.parse(line); if (record.sessionId && record.timestamp) { const timestamp = new Date(record.timestamp); if (timestamp >= dayStart && timestamp <= dayEnd) { sessionIds.add(record.sessionId); } break; } } catch { } } } } return sessionIds.size; } catch { return 0; } } function countRounds(dayStart, dayEnd) { try { const historyPath = path.join(os.homedir(), '.claude', 'history.jsonl'); if (!fs.existsSync(historyPath)) return 0; let count = 0; const content = fs.readFileSync(historyPath, 'utf8'); const lines = content.trim().split('\n').filter(line => line.trim()); for (const line of lines) { try { const entry = JSON.parse(line); const display = entry.display?.trim() || ''; if (!display || display.startsWith('/')) continue; const timestamp = new Date(entry.timestamp || entry.createdAt || 0); if (timestamp >= dayStart && timestamp <= dayEnd) { count++; } } catch { } } return count; } catch { return 0; } } function countCodeChanges(dayStart, dayEnd) { try { const projectsDir = path.join(os.homedir(), '.claude', 'projects'); if (!fs.existsSync(projectsDir)) return { added: 0, deleted: 0 }; let added = 0; let deleted = 0; const projectDirs = fs.readdirSync(projectsDir); for (const dir of projectDirs) { const dirPath = path.join(projectsDir, dir); if (!fs.statSync(dirPath).isDirectory()) continue; const files = fs.readdirSync(dirPath).filter(f => f.endsWith('.jsonl')); for (const file of files) { const filePath = path.join(dirPath, file); const content = fs.readFileSync(filePath, 'utf8'); const lines = content.trim().split('\n'); for (const line of lines) { try { const record = JSON.parse(line); if (!record.timestamp) continue; const timestamp = new Date(record.timestamp); if (timestamp < dayStart || timestamp > dayEnd) continue; if (record.type === 'assistant' && record.message?.content) { for (const item of record.message.content) { if (item.type === 'tool_use' && item.input) { const { name, input } = item; if (name === 'Edit') { const oldLines = (input.old_string || '').split('\n').length; const newLines = (input.new_string || '').split('\n').length; if (newLines > oldLines) { added += newLines - oldLines; } else { deleted += oldLines - newLines; } } else if (name === 'Write') { const lineCount = (input.content || '').split('\n').length; added += lineCount; } } } } } catch { } } } } return { added, deleted }; } catch { return { added: 0, deleted: 0 }; } } //# sourceMappingURL=cli-legacy.js.map