cc-code-status 1.1.6 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +295 -39
- package/dist/cli-legacy.d.ts +13 -0
- package/dist/cli-legacy.d.ts.map +1 -0
- package/dist/cli-legacy.js +535 -0
- package/dist/cli-legacy.js.map +1 -0
- package/dist/cli.backup.d.ts +3 -0
- package/dist/cli.backup.d.ts.map +1 -0
- package/dist/cli.backup.js +661 -0
- package/dist/cli.backup.js.map +1 -0
- package/dist/cli.d.ts +6 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +423 -570
- package/dist/cli.js.map +1 -1
- package/dist/config/constants.d.ts +17 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +42 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/config/manager.d.ts +121 -0
- package/dist/config/manager.d.ts.map +1 -0
- package/dist/config/manager.js +273 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/validator.d.ts +17 -0
- package/dist/config/validator.d.ts.map +1 -0
- package/dist/config/validator.js +39 -0
- package/dist/config/validator.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -1
- package/dist/launcher.d.ts +27 -0
- package/dist/launcher.d.ts.map +1 -0
- package/dist/launcher.js +145 -0
- package/dist/launcher.js.map +1 -0
- package/dist/ui/prompts.d.ts +34 -0
- package/dist/ui/prompts.d.ts.map +1 -0
- package/dist/ui/prompts.js +192 -0
- package/dist/ui/prompts.js.map +1 -0
- package/dist/ui/welcome.d.ts +30 -0
- package/dist/ui/welcome.d.ts.map +1 -0
- package/dist/ui/welcome.js +95 -0
- package/dist/ui/welcome.js.map +1 -0
- package/dist/utils/installer.d.ts +15 -0
- package/dist/utils/installer.d.ts.map +1 -0
- package/dist/utils/installer.js +56 -0
- package/dist/utils/installer.js.map +1 -0
- package/dist/utils/logger.d.ts +12 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +32 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +16 -4
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
// CLI 用于全局安装 - 处理状态栏执行和设置
|
|
41
|
+
const args = process.argv.slice(2);
|
|
42
|
+
const command = args[0];
|
|
43
|
+
if (command === 'setup' || command === 'install') {
|
|
44
|
+
// 运行设置
|
|
45
|
+
setup();
|
|
46
|
+
}
|
|
47
|
+
else if (command === 'uninstall') {
|
|
48
|
+
// 运行卸载
|
|
49
|
+
uninstall();
|
|
50
|
+
}
|
|
51
|
+
else if (command === 'sync-enable') {
|
|
52
|
+
// 启用数据上报
|
|
53
|
+
setSyncEnabled(true);
|
|
54
|
+
}
|
|
55
|
+
else if (command === 'sync-disable') {
|
|
56
|
+
// 禁用数据上报
|
|
57
|
+
setSyncEnabled(false);
|
|
58
|
+
}
|
|
59
|
+
else if (command === 'sync-status') {
|
|
60
|
+
// 查看数据上报状态
|
|
61
|
+
showSyncStatus();
|
|
62
|
+
}
|
|
63
|
+
else if (command === 'sync-now' || command === 'sync') {
|
|
64
|
+
// 主动触发一次数据上报
|
|
65
|
+
const { StatusLinePlugin } = require('./index');
|
|
66
|
+
StatusLinePlugin.manualSync();
|
|
67
|
+
}
|
|
68
|
+
else if (command === 'custom-sync') {
|
|
69
|
+
// 自定义数据上报
|
|
70
|
+
customSync();
|
|
71
|
+
}
|
|
72
|
+
else if (command === 'week') {
|
|
73
|
+
// 显示本周统计
|
|
74
|
+
showWeekStats();
|
|
75
|
+
}
|
|
76
|
+
else if (command === 'exclude') {
|
|
77
|
+
// 排除项目管理
|
|
78
|
+
const subCommand = args[1];
|
|
79
|
+
const projectPath = args[2];
|
|
80
|
+
if (subCommand === 'add' && projectPath) {
|
|
81
|
+
const { StatusLinePlugin } = require('./index');
|
|
82
|
+
StatusLinePlugin.addExcludedProject(projectPath);
|
|
83
|
+
}
|
|
84
|
+
else if (subCommand === 'remove' && projectPath) {
|
|
85
|
+
const { StatusLinePlugin } = require('./index');
|
|
86
|
+
StatusLinePlugin.removeExcludedProject(projectPath);
|
|
87
|
+
}
|
|
88
|
+
else if (subCommand === 'list') {
|
|
89
|
+
const { StatusLinePlugin } = require('./index');
|
|
90
|
+
StatusLinePlugin.listExcludedProjects();
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.log('');
|
|
94
|
+
console.log('用法:');
|
|
95
|
+
console.log(' cc-code-status exclude add <项目路径> 添加排除项目');
|
|
96
|
+
console.log(' cc-code-status exclude remove <项目路径> 移除排除项目');
|
|
97
|
+
console.log(' cc-code-status exclude list 列出排除项目');
|
|
98
|
+
console.log('');
|
|
99
|
+
console.log('示例:');
|
|
100
|
+
console.log(' cc-code-status exclude add /Users/qilin/test-project');
|
|
101
|
+
console.log(' cc-code-status exclude add .');
|
|
102
|
+
console.log(' cc-code-status exclude remove /Users/qilin/test-project');
|
|
103
|
+
console.log(' cc-code-status exclude list');
|
|
104
|
+
console.log('');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else if (command === 'help' || command === '--help' || command === '-h') {
|
|
108
|
+
// 显示帮助
|
|
109
|
+
showHelp();
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// 默认:作为状态栏插件运行(用于 Claude Code)
|
|
113
|
+
const { StatusLinePlugin } = require('./index');
|
|
114
|
+
const plugin = new StatusLinePlugin();
|
|
115
|
+
plugin.run().catch(() => {
|
|
116
|
+
console.log('Error');
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function setup() {
|
|
120
|
+
console.log('🚀 设置 CC Code Status 插件...');
|
|
121
|
+
const claudeSettingsDir = path.join(os.homedir(), '.claude');
|
|
122
|
+
const claudeSettingsFile = path.join(claudeSettingsDir, 'settings.json');
|
|
123
|
+
// 如果 .claude 目录不存在则创建
|
|
124
|
+
if (!fs.existsSync(claudeSettingsDir)) {
|
|
125
|
+
console.log('📁 创建 Claude 设置目录...');
|
|
126
|
+
fs.mkdirSync(claudeSettingsDir, { recursive: true });
|
|
127
|
+
}
|
|
128
|
+
// 获取全局命令路径
|
|
129
|
+
const commandPath = 'cc-code-status';
|
|
130
|
+
// 创建或更新 settings.json
|
|
131
|
+
let settings = {};
|
|
132
|
+
if (fs.existsSync(claudeSettingsFile)) {
|
|
133
|
+
console.log('📝 更新现有 settings.json...');
|
|
134
|
+
// 备份现有设置
|
|
135
|
+
const backupFile = `${claudeSettingsFile}.backup`;
|
|
136
|
+
fs.copyFileSync(claudeSettingsFile, backupFile);
|
|
137
|
+
console.log(` 备份保存至: ${backupFile}`);
|
|
138
|
+
try {
|
|
139
|
+
const existingContent = fs.readFileSync(claudeSettingsFile, 'utf8');
|
|
140
|
+
settings = JSON.parse(existingContent);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
console.error('⚠️ 读取现有设置出错,创建新设置...');
|
|
144
|
+
settings = {};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
console.log('📝 创建新的 settings.json...');
|
|
149
|
+
}
|
|
150
|
+
// 更新 statusLine 配置
|
|
151
|
+
settings.statusLine = {
|
|
152
|
+
type: 'command',
|
|
153
|
+
command: commandPath
|
|
154
|
+
};
|
|
155
|
+
// 写入更新后的设置
|
|
156
|
+
fs.writeFileSync(claudeSettingsFile, JSON.stringify(settings, null, 2));
|
|
157
|
+
console.log('✅ 设置更新成功!');
|
|
158
|
+
console.log('');
|
|
159
|
+
console.log('🎉 CC Code Status 插件已配置完成!');
|
|
160
|
+
console.log('');
|
|
161
|
+
console.log('插件将显示:');
|
|
162
|
+
console.log(' 📁 当前目录名称');
|
|
163
|
+
console.log(' 👤 Git 用户名');
|
|
164
|
+
console.log('');
|
|
165
|
+
console.log('卸载: npm uninstall -g cc-code-status');
|
|
166
|
+
}
|
|
167
|
+
function uninstall() {
|
|
168
|
+
console.log('🗑️ 移除 CC Code Status 插件配置...');
|
|
169
|
+
const claudeSettingsFile = path.join(os.homedir(), '.claude', 'settings.json');
|
|
170
|
+
if (!fs.existsSync(claudeSettingsFile)) {
|
|
171
|
+
console.log('⚠️ 未找到 Claude 设置文件。');
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
const content = fs.readFileSync(claudeSettingsFile, 'utf8');
|
|
176
|
+
const settings = JSON.parse(content);
|
|
177
|
+
if (settings.statusLine) {
|
|
178
|
+
delete settings.statusLine;
|
|
179
|
+
fs.writeFileSync(claudeSettingsFile, JSON.stringify(settings, null, 2));
|
|
180
|
+
console.log('✅ StatusLine 配置已从 Claude 设置中移除。');
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
console.log('⚠️ 设置中未找到 statusLine 配置。');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
console.error('❌ 更新设置时出错:', error);
|
|
188
|
+
}
|
|
189
|
+
console.log('');
|
|
190
|
+
console.log('完成卸载请运行:');
|
|
191
|
+
console.log(' npm uninstall -g cc-code-status');
|
|
192
|
+
}
|
|
193
|
+
function setSyncEnabled(enabled) {
|
|
194
|
+
const configDir = path.join(os.homedir(), '.cc-code-status');
|
|
195
|
+
const configFile = path.join(configDir, 'config.json');
|
|
196
|
+
// 确保目录存在
|
|
197
|
+
if (!fs.existsSync(configDir)) {
|
|
198
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
199
|
+
}
|
|
200
|
+
// 读取现有配置
|
|
201
|
+
let config = {
|
|
202
|
+
apiUrl: 'http://10.40.0.70:8087/api/cloudcode-ai/batch-receive',
|
|
203
|
+
syncInterval: 1800000,
|
|
204
|
+
enabled: false
|
|
205
|
+
};
|
|
206
|
+
if (fs.existsSync(configFile)) {
|
|
207
|
+
try {
|
|
208
|
+
const content = fs.readFileSync(configFile, 'utf8');
|
|
209
|
+
config = JSON.parse(content);
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
console.error('⚠️ 读取配置文件失败,使用默认配置');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// 更新 enabled 状态
|
|
216
|
+
config.enabled = enabled;
|
|
217
|
+
// 写入配置
|
|
218
|
+
try {
|
|
219
|
+
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
|
|
220
|
+
console.log('');
|
|
221
|
+
if (enabled) {
|
|
222
|
+
console.log('✅ 数据上报功能已启用');
|
|
223
|
+
console.log('');
|
|
224
|
+
console.log(`📡 API 地址: ${config.apiUrl}`);
|
|
225
|
+
console.log(`⏱️ 同步间隔: ${config.syncInterval / 1000 / 60} 分钟`);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
console.log('✅ 数据上报功能已禁用');
|
|
229
|
+
}
|
|
230
|
+
console.log('');
|
|
231
|
+
console.log(`配置文件: ${configFile}`);
|
|
232
|
+
console.log('');
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
console.error('❌ 写入配置文件失败:', error);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function showSyncStatus() {
|
|
239
|
+
const configFile = path.join(os.homedir(), '.cc-code-status', 'config.json');
|
|
240
|
+
if (!fs.existsSync(configFile)) {
|
|
241
|
+
console.log('');
|
|
242
|
+
console.log('⚠️ 配置文件不存在');
|
|
243
|
+
console.log('');
|
|
244
|
+
console.log('运行以下命令启用数据上报:');
|
|
245
|
+
console.log(' cc-code-status sync-enable');
|
|
246
|
+
console.log('');
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
const content = fs.readFileSync(configFile, 'utf8');
|
|
251
|
+
const config = JSON.parse(content);
|
|
252
|
+
console.log('');
|
|
253
|
+
console.log('========================================');
|
|
254
|
+
console.log(' 数据上报状态');
|
|
255
|
+
console.log('========================================');
|
|
256
|
+
console.log('');
|
|
257
|
+
console.log(`状态: ${config.enabled ? '✅ 已启用' : '❌ 已禁用'}`);
|
|
258
|
+
console.log(`API 地址: ${config.apiUrl || '(未配置)'}`);
|
|
259
|
+
console.log(`同步间隔: ${(config.syncInterval || 1800000) / 1000 / 60} 分钟`);
|
|
260
|
+
console.log('');
|
|
261
|
+
console.log(`配置文件: ${configFile}`);
|
|
262
|
+
console.log('');
|
|
263
|
+
if (config.enabled) {
|
|
264
|
+
console.log('要禁用数据上报,运行:');
|
|
265
|
+
console.log(' cc-code-status sync-disable');
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
console.log('要启用数据上报,运行:');
|
|
269
|
+
console.log(' cc-code-status sync-enable');
|
|
270
|
+
}
|
|
271
|
+
console.log('');
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
console.error('❌ 读取配置失败:', error);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
function customSync() {
|
|
278
|
+
const readline = require('readline');
|
|
279
|
+
const { execSync } = require('child_process');
|
|
280
|
+
const rl = readline.createInterface({
|
|
281
|
+
input: process.stdin,
|
|
282
|
+
output: process.stdout
|
|
283
|
+
});
|
|
284
|
+
console.log('');
|
|
285
|
+
console.log('========================================');
|
|
286
|
+
console.log(' 自定义数据上报');
|
|
287
|
+
console.log('========================================');
|
|
288
|
+
console.log('');
|
|
289
|
+
// 获取 git 用户名
|
|
290
|
+
let username = 'Unknown';
|
|
291
|
+
try {
|
|
292
|
+
username = execSync('git config user.name', {
|
|
293
|
+
encoding: 'utf8',
|
|
294
|
+
stdio: ['pipe', 'pipe', 'ignore']
|
|
295
|
+
}).trim();
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
// 忽略错误
|
|
299
|
+
}
|
|
300
|
+
// 使用 Promise 包装 readline 问答
|
|
301
|
+
const askQuestion = (question) => {
|
|
302
|
+
return new Promise((resolve) => {
|
|
303
|
+
rl.question(question, (answer) => {
|
|
304
|
+
resolve(answer.trim());
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
};
|
|
308
|
+
// 交互式输入数据
|
|
309
|
+
(async () => {
|
|
310
|
+
try {
|
|
311
|
+
// 检查是否启用了同步功能
|
|
312
|
+
const configFile = path.join(os.homedir(), '.cc-code-status', 'config.json');
|
|
313
|
+
if (!fs.existsSync(configFile)) {
|
|
314
|
+
console.log('❌ 配置文件不存在,请先运行: cc-code-status sync-enable');
|
|
315
|
+
console.log('');
|
|
316
|
+
rl.close();
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const configContent = fs.readFileSync(configFile, 'utf8');
|
|
320
|
+
const config = JSON.parse(configContent);
|
|
321
|
+
if (!config.enabled) {
|
|
322
|
+
console.log('❌ 数据上报功能未启用');
|
|
323
|
+
console.log('');
|
|
324
|
+
console.log('请先运行以下命令启用数据上报:');
|
|
325
|
+
console.log(' cc-code-status sync-enable');
|
|
326
|
+
console.log('');
|
|
327
|
+
rl.close();
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (!config.apiUrl) {
|
|
331
|
+
console.log('❌ API 地址未配置');
|
|
332
|
+
console.log('');
|
|
333
|
+
console.log(`请在配置文件中设置 apiUrl: ${configFile}`);
|
|
334
|
+
console.log('');
|
|
335
|
+
rl.close();
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
console.log(`当前用户: ${username}`);
|
|
339
|
+
console.log('');
|
|
340
|
+
// 输入对话轮次
|
|
341
|
+
const roundsInput = await askQuestion('请输入对话轮次: ');
|
|
342
|
+
const rounds = parseInt(roundsInput, 10);
|
|
343
|
+
if (isNaN(rounds) || rounds < 0) {
|
|
344
|
+
console.log('');
|
|
345
|
+
console.log('❌ 对话轮次必须是非负整数');
|
|
346
|
+
console.log('');
|
|
347
|
+
rl.close();
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
// 输入新增代码行数
|
|
351
|
+
const addedInput = await askQuestion('请输入新增代码行数: ');
|
|
352
|
+
const codeAdded = parseInt(addedInput, 10);
|
|
353
|
+
if (isNaN(codeAdded) || codeAdded < 0) {
|
|
354
|
+
console.log('');
|
|
355
|
+
console.log('❌ 新增代码行数必须是非负整数');
|
|
356
|
+
console.log('');
|
|
357
|
+
rl.close();
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
// 输入删除代码行数
|
|
361
|
+
const deletedInput = await askQuestion('请输入删除代码行数: ');
|
|
362
|
+
const codeDeleted = parseInt(deletedInput, 10);
|
|
363
|
+
if (isNaN(codeDeleted) || codeDeleted < 0) {
|
|
364
|
+
console.log('');
|
|
365
|
+
console.log('❌ 删除代码行数必须是非负整数');
|
|
366
|
+
console.log('');
|
|
367
|
+
rl.close();
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
console.log('');
|
|
371
|
+
console.log('数据汇总:');
|
|
372
|
+
console.log(` 用户: ${username}`);
|
|
373
|
+
console.log(` 对话轮次: ${rounds}`);
|
|
374
|
+
console.log(` 新增代码: ${codeAdded} 行`);
|
|
375
|
+
console.log(` 删除代码: ${codeDeleted} 行`);
|
|
376
|
+
console.log('');
|
|
377
|
+
// 确认上报
|
|
378
|
+
const confirm = await askQuestion('确认上报以上数据?(y/n): ');
|
|
379
|
+
if (confirm.toLowerCase() !== 'y' && confirm.toLowerCase() !== 'yes') {
|
|
380
|
+
console.log('');
|
|
381
|
+
console.log('❌ 已取消上报');
|
|
382
|
+
console.log('');
|
|
383
|
+
rl.close();
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
// 构造 ConversationDetail 对象
|
|
387
|
+
const today = new Date();
|
|
388
|
+
const dateString = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
|
|
389
|
+
const conversationDetail = {
|
|
390
|
+
id: `custom-${Date.now()}`,
|
|
391
|
+
userId: username,
|
|
392
|
+
userName: username,
|
|
393
|
+
conversationCount: rounds,
|
|
394
|
+
adoptedLines: codeAdded + codeDeleted,
|
|
395
|
+
codeAdded: codeAdded,
|
|
396
|
+
codeDeleted: codeDeleted,
|
|
397
|
+
messages: [],
|
|
398
|
+
createDate: dateString,
|
|
399
|
+
updatedAt: dateString
|
|
400
|
+
};
|
|
401
|
+
// 调用 StatusLinePlugin 的上报方法
|
|
402
|
+
const { StatusLinePlugin } = require('./index');
|
|
403
|
+
const plugin = new StatusLinePlugin();
|
|
404
|
+
// 直接调用 syncToBackend 方法(需要使其可访问)
|
|
405
|
+
plugin.syncToBackend(config.apiUrl, [conversationDetail]);
|
|
406
|
+
console.log('');
|
|
407
|
+
console.log('✅ 数据已提交上报');
|
|
408
|
+
console.log('');
|
|
409
|
+
console.log('注: 上报结果请查看服务端日志');
|
|
410
|
+
console.log('');
|
|
411
|
+
rl.close();
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
console.log('');
|
|
415
|
+
console.log('❌ 上报失败:', error);
|
|
416
|
+
console.log('');
|
|
417
|
+
rl.close();
|
|
418
|
+
}
|
|
419
|
+
})();
|
|
420
|
+
}
|
|
421
|
+
function showHelp() {
|
|
422
|
+
console.log('CC Code Status Plugin - Claude Code git 用户信息显示');
|
|
423
|
+
console.log('');
|
|
424
|
+
console.log('用法:');
|
|
425
|
+
console.log(' cc-code-status 作为状态栏插件运行(由 Claude Code 使用)');
|
|
426
|
+
console.log(' cc-code-status setup 配置 Claude Code 使用此插件');
|
|
427
|
+
console.log(' cc-code-status uninstall 从 Claude Code 中移除插件配置');
|
|
428
|
+
console.log(' cc-code-status sync-enable 启用数据上报功能');
|
|
429
|
+
console.log(' cc-code-status sync-disable 禁用数据上报功能');
|
|
430
|
+
console.log(' cc-code-status sync-status 查看数据上报状态');
|
|
431
|
+
console.log(' cc-code-status sync-now 主动触发一次数据上报');
|
|
432
|
+
console.log(' cc-code-status week 显示本周统计(对话次数/轮数、代码行数)');
|
|
433
|
+
console.log(' cc-code-status exclude add <路径> 添加排除项目(不统计该项目)');
|
|
434
|
+
console.log(' cc-code-status exclude remove <路径> 移除排除项目');
|
|
435
|
+
console.log(' cc-code-status exclude list 列出所有排除项目');
|
|
436
|
+
console.log(' cc-code-status help 显示此帮助信息');
|
|
437
|
+
console.log('');
|
|
438
|
+
console.log('别名: 所有命令都支持短别名 ccs(如 ccs sync-now, ccs exclude list)');
|
|
439
|
+
console.log('');
|
|
440
|
+
console.log('安装:');
|
|
441
|
+
console.log(' npm install -g cc-code-status');
|
|
442
|
+
console.log('');
|
|
443
|
+
console.log('安装后插件会自动配置。');
|
|
444
|
+
}
|
|
445
|
+
function showWeekStats() {
|
|
446
|
+
const { execSync } = require('child_process');
|
|
447
|
+
try {
|
|
448
|
+
// 获取 git 用户名
|
|
449
|
+
let username = 'Unknown';
|
|
450
|
+
try {
|
|
451
|
+
username = execSync('git config user.name', {
|
|
452
|
+
encoding: 'utf8',
|
|
453
|
+
stdio: ['pipe', 'pipe', 'ignore']
|
|
454
|
+
}).trim();
|
|
455
|
+
}
|
|
456
|
+
catch {
|
|
457
|
+
// 忽略错误
|
|
458
|
+
}
|
|
459
|
+
// 计算本周的日期范围(周一到周日)
|
|
460
|
+
const today = new Date();
|
|
461
|
+
const dayOfWeek = today.getDay(); // 0=周日, 1=周一, ..., 6=周六
|
|
462
|
+
const daysToMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1; // 到本周一的天数
|
|
463
|
+
const weekStart = new Date(today);
|
|
464
|
+
weekStart.setDate(today.getDate() - daysToMonday);
|
|
465
|
+
weekStart.setHours(0, 0, 0, 0);
|
|
466
|
+
const weekEnd = new Date(weekStart);
|
|
467
|
+
weekEnd.setDate(weekStart.getDate() + 6);
|
|
468
|
+
weekEnd.setHours(23, 59, 59, 999);
|
|
469
|
+
// 收集本周每一天的数据
|
|
470
|
+
const dailyStats = [];
|
|
471
|
+
let totalConversations = 0;
|
|
472
|
+
let totalRounds = 0;
|
|
473
|
+
let totalAdded = 0;
|
|
474
|
+
let totalDeleted = 0;
|
|
475
|
+
const dayNames = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
|
476
|
+
for (let i = 0; i < 7; i++) {
|
|
477
|
+
const currentDay = new Date(weekStart);
|
|
478
|
+
currentDay.setDate(weekStart.getDate() + i);
|
|
479
|
+
const dayStart = new Date(currentDay);
|
|
480
|
+
dayStart.setHours(0, 0, 0, 0);
|
|
481
|
+
const dayEnd = new Date(currentDay);
|
|
482
|
+
dayEnd.setHours(23, 59, 59, 999);
|
|
483
|
+
const conversations = countConversations(dayStart, dayEnd);
|
|
484
|
+
const rounds = countRounds(dayStart, dayEnd);
|
|
485
|
+
const codeStats = countCodeChanges(dayStart, dayEnd);
|
|
486
|
+
totalConversations += conversations;
|
|
487
|
+
totalRounds += rounds;
|
|
488
|
+
totalAdded += codeStats.added;
|
|
489
|
+
totalDeleted += codeStats.deleted;
|
|
490
|
+
dailyStats.push({
|
|
491
|
+
date: formatDate(currentDay),
|
|
492
|
+
dayName: dayNames[currentDay.getDay()],
|
|
493
|
+
conversations,
|
|
494
|
+
rounds,
|
|
495
|
+
codeAdded: codeStats.added,
|
|
496
|
+
codeDeleted: codeStats.deleted
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
// 输出结果
|
|
500
|
+
console.log('');
|
|
501
|
+
console.log('========================================');
|
|
502
|
+
console.log(` 本周统计 (${formatDate(weekStart)} 至 ${formatDate(weekEnd)})`);
|
|
503
|
+
console.log('========================================');
|
|
504
|
+
console.log('');
|
|
505
|
+
console.log(`总计: ${totalConversations}次/${totalRounds}轮 | +${totalAdded}/-${totalDeleted} 行`);
|
|
506
|
+
console.log('');
|
|
507
|
+
console.log('每日明细:');
|
|
508
|
+
console.log('');
|
|
509
|
+
for (const day of dailyStats) {
|
|
510
|
+
const dateStr = `${day.dayName} (${day.date})`;
|
|
511
|
+
const statsStr = `${day.conversations}次/${day.rounds}轮 | +${day.codeAdded}/-${day.codeDeleted} 行`;
|
|
512
|
+
console.log(` ${dateStr.padEnd(20)} ${statsStr}`);
|
|
513
|
+
}
|
|
514
|
+
console.log('');
|
|
515
|
+
}
|
|
516
|
+
catch (error) {
|
|
517
|
+
console.error('❌ 统计失败:', error);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
// ========== 辅助函数 ==========
|
|
521
|
+
function formatDate(date) {
|
|
522
|
+
const year = date.getFullYear();
|
|
523
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
524
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
525
|
+
return `${year}-${month}-${day}`;
|
|
526
|
+
}
|
|
527
|
+
function countConversations(dayStart, dayEnd) {
|
|
528
|
+
try {
|
|
529
|
+
const projectsDir = path.join(os.homedir(), '.claude', 'projects');
|
|
530
|
+
if (!fs.existsSync(projectsDir)) {
|
|
531
|
+
return 0;
|
|
532
|
+
}
|
|
533
|
+
const sessionIds = new Set();
|
|
534
|
+
const projectDirs = fs.readdirSync(projectsDir);
|
|
535
|
+
for (const dir of projectDirs) {
|
|
536
|
+
const dirPath = path.join(projectsDir, dir);
|
|
537
|
+
if (!fs.statSync(dirPath).isDirectory())
|
|
538
|
+
continue;
|
|
539
|
+
const files = fs.readdirSync(dirPath).filter(f => f.endsWith('.jsonl') && !f.startsWith('agent-'));
|
|
540
|
+
for (const file of files) {
|
|
541
|
+
const filePath = path.join(dirPath, file);
|
|
542
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
543
|
+
const lines = content.trim().split('\n');
|
|
544
|
+
if (lines.length === 0)
|
|
545
|
+
continue;
|
|
546
|
+
for (const line of lines) {
|
|
547
|
+
try {
|
|
548
|
+
const record = JSON.parse(line);
|
|
549
|
+
if (record.sessionId && record.timestamp) {
|
|
550
|
+
const timestamp = new Date(record.timestamp);
|
|
551
|
+
if (timestamp >= dayStart && timestamp <= dayEnd) {
|
|
552
|
+
sessionIds.add(record.sessionId);
|
|
553
|
+
}
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
catch {
|
|
558
|
+
// 忽略解析错误
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
return sessionIds.size;
|
|
564
|
+
}
|
|
565
|
+
catch {
|
|
566
|
+
return 0;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
function countRounds(dayStart, dayEnd) {
|
|
570
|
+
try {
|
|
571
|
+
const historyPath = path.join(os.homedir(), '.claude', 'history.jsonl');
|
|
572
|
+
if (!fs.existsSync(historyPath)) {
|
|
573
|
+
return 0;
|
|
574
|
+
}
|
|
575
|
+
let count = 0;
|
|
576
|
+
const content = fs.readFileSync(historyPath, 'utf8');
|
|
577
|
+
const lines = content.trim().split('\n').filter(line => line.trim());
|
|
578
|
+
for (const line of lines) {
|
|
579
|
+
try {
|
|
580
|
+
const entry = JSON.parse(line);
|
|
581
|
+
const display = entry.display?.trim() || '';
|
|
582
|
+
if (!display || display.startsWith('/')) {
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
const timestamp = new Date(entry.timestamp || entry.createdAt || 0);
|
|
586
|
+
if (timestamp >= dayStart && timestamp <= dayEnd) {
|
|
587
|
+
count++;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
catch {
|
|
591
|
+
// 忽略解析错误
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return count;
|
|
595
|
+
}
|
|
596
|
+
catch {
|
|
597
|
+
return 0;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
function countCodeChanges(dayStart, dayEnd) {
|
|
601
|
+
try {
|
|
602
|
+
const projectsDir = path.join(os.homedir(), '.claude', 'projects');
|
|
603
|
+
if (!fs.existsSync(projectsDir)) {
|
|
604
|
+
return { added: 0, deleted: 0 };
|
|
605
|
+
}
|
|
606
|
+
let added = 0;
|
|
607
|
+
let deleted = 0;
|
|
608
|
+
const projectDirs = fs.readdirSync(projectsDir);
|
|
609
|
+
for (const dir of projectDirs) {
|
|
610
|
+
const dirPath = path.join(projectsDir, dir);
|
|
611
|
+
if (!fs.statSync(dirPath).isDirectory())
|
|
612
|
+
continue;
|
|
613
|
+
const files = fs.readdirSync(dirPath).filter(f => f.endsWith('.jsonl'));
|
|
614
|
+
for (const file of files) {
|
|
615
|
+
const filePath = path.join(dirPath, file);
|
|
616
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
617
|
+
const lines = content.trim().split('\n');
|
|
618
|
+
for (const line of lines) {
|
|
619
|
+
try {
|
|
620
|
+
const record = JSON.parse(line);
|
|
621
|
+
if (!record.timestamp)
|
|
622
|
+
continue;
|
|
623
|
+
const timestamp = new Date(record.timestamp);
|
|
624
|
+
if (timestamp < dayStart || timestamp > dayEnd) {
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
if (record.type === 'assistant' && record.message?.content) {
|
|
628
|
+
for (const item of record.message.content) {
|
|
629
|
+
if (item.type === 'tool_use' && item.input) {
|
|
630
|
+
const { name, input } = item;
|
|
631
|
+
if (name === 'Edit') {
|
|
632
|
+
const oldLines = (input.old_string || '').split('\n').length;
|
|
633
|
+
const newLines = (input.new_string || '').split('\n').length;
|
|
634
|
+
if (newLines > oldLines) {
|
|
635
|
+
added += newLines - oldLines;
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
deleted += oldLines - newLines;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
else if (name === 'Write') {
|
|
642
|
+
const lineCount = (input.content || '').split('\n').length;
|
|
643
|
+
added += lineCount;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
catch {
|
|
650
|
+
// 忽略解析错误
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return { added, deleted };
|
|
656
|
+
}
|
|
657
|
+
catch {
|
|
658
|
+
return { added: 0, deleted: 0 };
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
//# sourceMappingURL=cli.backup.js.map
|