cc-code-status
Version:
Enhanced Claude Code launcher with statusline - supports multiple custom API configurations and code statistics
535 lines • 20.8 kB
JavaScript
;
/**
* 旧版 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