cc-code-status 1.1.6 → 2.0.2

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.
Files changed (50) hide show
  1. package/README.md +295 -39
  2. package/dist/cli-legacy.d.ts +13 -0
  3. package/dist/cli-legacy.d.ts.map +1 -0
  4. package/dist/cli-legacy.js +535 -0
  5. package/dist/cli-legacy.js.map +1 -0
  6. package/dist/cli.backup.d.ts +3 -0
  7. package/dist/cli.backup.d.ts.map +1 -0
  8. package/dist/cli.backup.js +661 -0
  9. package/dist/cli.backup.js.map +1 -0
  10. package/dist/cli.d.ts +6 -1
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +423 -570
  13. package/dist/cli.js.map +1 -1
  14. package/dist/config/constants.d.ts +17 -0
  15. package/dist/config/constants.d.ts.map +1 -0
  16. package/dist/config/constants.js +42 -0
  17. package/dist/config/constants.js.map +1 -0
  18. package/dist/config/manager.d.ts +121 -0
  19. package/dist/config/manager.d.ts.map +1 -0
  20. package/dist/config/manager.js +273 -0
  21. package/dist/config/manager.js.map +1 -0
  22. package/dist/config/validator.d.ts +17 -0
  23. package/dist/config/validator.d.ts.map +1 -0
  24. package/dist/config/validator.js +39 -0
  25. package/dist/config/validator.js.map +1 -0
  26. package/dist/index.d.ts +10 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +27 -0
  29. package/dist/index.js.map +1 -1
  30. package/dist/launcher.d.ts +27 -0
  31. package/dist/launcher.d.ts.map +1 -0
  32. package/dist/launcher.js +149 -0
  33. package/dist/launcher.js.map +1 -0
  34. package/dist/ui/prompts.d.ts +34 -0
  35. package/dist/ui/prompts.d.ts.map +1 -0
  36. package/dist/ui/prompts.js +192 -0
  37. package/dist/ui/prompts.js.map +1 -0
  38. package/dist/ui/welcome.d.ts +30 -0
  39. package/dist/ui/welcome.d.ts.map +1 -0
  40. package/dist/ui/welcome.js +95 -0
  41. package/dist/ui/welcome.js.map +1 -0
  42. package/dist/utils/installer.d.ts +20 -0
  43. package/dist/utils/installer.d.ts.map +1 -0
  44. package/dist/utils/installer.js +68 -0
  45. package/dist/utils/installer.js.map +1 -0
  46. package/dist/utils/logger.d.ts +12 -0
  47. package/dist/utils/logger.d.ts.map +1 -0
  48. package/dist/utils/logger.js +32 -0
  49. package/dist/utils/logger.js.map +1 -0
  50. package/package.json +16 -4
package/dist/cli.js CHANGED
@@ -1,5 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
+ /**
4
+ * CLI 主入口
5
+ * v2.0.0 - 增强版 Claude Code 启动器 + 状态栏插件
6
+ */
3
7
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
8
  if (k2 === undefined) k2 = k;
5
9
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -33,629 +37,478 @@ var __importStar = (this && this.__importStar) || (function () {
33
37
  return result;
34
38
  };
35
39
  })();
40
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41
+ return (mod && mod.__esModule) ? mod : { "default": mod };
42
+ };
36
43
  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 用于全局安装 - 处理状态栏执行和设置
44
+ exports.main = main;
45
+ const chalk_1 = __importDefault(require("chalk"));
46
+ const inquirer_1 = __importDefault(require("inquirer"));
47
+ const manager_1 = require("./config/manager");
48
+ const launcher_1 = require("./launcher");
49
+ const prompts_1 = require("./ui/prompts");
50
+ const welcome_1 = require("./ui/welcome");
51
+ const installer_1 = require("./utils/installer");
52
+ const logger_1 = require("./utils/logger");
53
+ const packageJson = require('../package.json');
54
+ // 解析命令行参数
41
55
  const args = process.argv.slice(2);
42
56
  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
- }
57
+ // 主函数
58
+ async function main() {
174
59
  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 设置中移除。');
60
+ // ========== 版本和帮助 ==========
61
+ if (args.includes('-v') || args.includes('--version')) {
62
+ console.log('CC Code Status v' + packageJson.version);
63
+ return;
181
64
  }
182
- else {
183
- console.log('⚠️ 设置中未找到 statusLine 配置。');
65
+ if (command === 'help' || command === '--help' || command === '-h') {
66
+ (0, welcome_1.showHelp)();
67
+ return;
184
68
  }
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);
69
+ // ========== 配置命令 ==========
70
+ if (command === 'config') {
71
+ await handleConfigCommand(args.slice(1));
72
+ return;
210
73
  }
211
- catch (error) {
212
- console.error('⚠️ 读取配置文件失败,使用默认配置');
74
+ // ========== 统计命令 ==========
75
+ if (command === 'stats' || command === 'week') {
76
+ await handleStatsCommand(args);
77
+ return;
213
78
  }
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} 分钟`);
79
+ // ========== 同步命令 ==========
80
+ if (command === 'sync-enable' || command === 'sync-disable' ||
81
+ command === 'sync-status' || command === 'sync-now' ||
82
+ command === 'sync' || command === 'custom-sync') {
83
+ await handleSyncCommand(args);
84
+ return;
226
85
  }
227
- else {
228
- console.log('✅ 数据上报功能已禁用');
86
+ // ========== 排除命令 ==========
87
+ if (command === 'exclude') {
88
+ await handleExcludeCommand(args.slice(1));
89
+ return;
229
90
  }
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');
91
+ // ========== 旧版命令(向后兼容)==========
92
+ if (command === 'setup' || command === 'install') {
93
+ await handleSetup();
94
+ return;
266
95
  }
267
- else {
268
- console.log('要启用数据上报,运行:');
269
- console.log(' cc-code-status sync-enable');
96
+ if (command === 'uninstall') {
97
+ await handleUninstall();
98
+ return;
270
99
  }
271
- console.log('');
100
+ // ========== 状态栏模式 ==========
101
+ // 检测是否为状态栏模式(通过 stdin 调用)
102
+ if (command === '--statusline' || !process.stdin.isTTY) {
103
+ await runAsStatusLine();
104
+ return;
105
+ }
106
+ // ========== 默认:启动器模式 ==========
107
+ await runAsLauncher(args);
272
108
  }
273
109
  catch (error) {
274
- console.error(' 读取配置失败:', error);
110
+ logger_1.Logger.error('程序执行失败: ' + error.message);
111
+ if (process.env.DEBUG) {
112
+ console.error(error);
113
+ }
114
+ process.exit(1);
275
115
  }
276
116
  }
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;
117
+ /**
118
+ * 处理 config 命令
119
+ */
120
+ async function handleConfigCommand(subArgs) {
121
+ const config = new manager_1.ConfigManager();
122
+ const subCommand = subArgs[0];
123
+ // config list - 列出所有配置
124
+ if (subCommand === 'list') {
125
+ const profiles = config.getAllProfiles();
126
+ if (profiles.length === 0) {
127
+ logger_1.Logger.warning('当前没有配置');
128
+ logger_1.Logger.info('运行 ccs config add 添加配置');
129
+ return;
130
+ }
131
+ console.log(chalk_1.default.cyan('\n📋 配置列表\n'));
132
+ console.log(chalk_1.default.gray('─'.repeat(70)));
133
+ profiles.forEach(p => {
134
+ const safeKey = p.apiKey.length > 12
135
+ ? `${p.apiKey.substring(0, 8)}...${p.apiKey.substring(p.apiKey.length - 4)}`
136
+ : '***';
137
+ // 从 baseUrl 提取域名
138
+ let domain = p.baseUrl;
139
+ try {
140
+ const url = new URL(p.baseUrl);
141
+ domain = url.hostname;
329
142
  }
330
- if (!config.apiUrl) {
331
- console.log('❌ API 地址未配置');
332
- console.log('');
333
- console.log(`请在配置文件中设置 apiUrl: ${configFile}`);
334
- console.log('');
335
- rl.close();
336
- return;
143
+ catch (e) {
144
+ // 如果不是有效 URL,使用原始值
337
145
  }
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;
146
+ console.log(chalk_1.default.white.bold('● ' + p.name));
147
+ console.log(chalk_1.default.gray(` Base URL: ${p.baseUrl}`));
148
+ console.log(chalk_1.default.gray(` API Key: ${safeKey}`));
149
+ if (p.model) {
150
+ console.log(chalk_1.default.gray(` Model: ${p.model}`));
349
151
  }
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;
152
+ if (p.smallFastModel) {
153
+ console.log(chalk_1.default.gray(` Small Fast Model: ${p.smallFastModel}`));
359
154
  }
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();
155
+ console.log('');
156
+ });
157
+ console.log(chalk_1.default.gray('─'.repeat(70)));
158
+ console.log(chalk_1.default.gray(`\n配置文件: ${config.getConfigPath()}\n`));
159
+ return;
160
+ }
161
+ // config add - 添加新配置
162
+ if (subCommand === 'add') {
163
+ (0, welcome_1.showWelcome)();
164
+ const answers = await (0, prompts_1.showConfigPrompts)();
165
+ // 检查配置是否已存在
166
+ if (config.hasProfile(answers.name)) {
167
+ const { confirm } = await inquirer_1.default.prompt([
168
+ {
169
+ type: 'confirm',
170
+ name: 'confirm',
171
+ message: chalk_1.default.yellow(`配置 "${answers.name}" 已存在,是否覆盖?`),
172
+ default: false
173
+ }
174
+ ]);
175
+ if (!confirm) {
176
+ logger_1.Logger.info('已取消');
368
177
  return;
369
178
  }
179
+ }
180
+ config.saveProfile(answers.name, {
181
+ apiKey: answers.apiKey,
182
+ baseUrl: answers.baseUrl,
183
+ model: answers.model,
184
+ smallFastModel: answers.smallFastModel
185
+ });
186
+ logger_1.Logger.success(`配置 "${answers.name}" 已保存`);
187
+ console.log('');
188
+ return;
189
+ }
190
+ // config remove <name> - 删除配置
191
+ if (subCommand === 'remove' || subCommand === 'rm') {
192
+ const name = subArgs[1];
193
+ if (!name) {
194
+ logger_1.Logger.error('请指定要删除的配置名称');
370
195
  console.log('');
371
- console.log('数据汇总:');
372
- console.log(` 用户: ${username}`);
373
- console.log(` 对话轮次: ${rounds}`);
374
- console.log(` 新增代码: ${codeAdded} 行`);
375
- console.log(` 删除代码: ${codeDeleted} 行`);
196
+ console.log('用法: ccs config remove <配置名称>');
376
197
  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;
198
+ return;
199
+ }
200
+ if (!config.hasProfile(name)) {
201
+ logger_1.Logger.error(`配置 "${name}" 不存在`);
202
+ console.log('');
203
+ console.log('使用 ccs config list 查看所有配置');
204
+ console.log('');
205
+ return;
206
+ }
207
+ const { confirm } = await inquirer_1.default.prompt([
208
+ {
209
+ type: 'confirm',
210
+ name: 'confirm',
211
+ message: chalk_1.default.yellow(`确定要删除配置 "${name}" 吗?`),
212
+ default: false
213
+ }
214
+ ]);
215
+ if (!confirm) {
216
+ logger_1.Logger.info('已取消');
217
+ return;
218
+ }
219
+ config.removeProfile(name);
220
+ logger_1.Logger.success(`配置 "${name}" 已删除`);
221
+ console.log('');
222
+ return;
223
+ }
224
+ // config show / config --show - 显示配置(单个配置时显示详情,多个配置时显示列表)
225
+ if (subCommand === 'show' || subArgs.includes('--show')) {
226
+ const profiles = config.getAllProfiles();
227
+ if (profiles.length === 0) {
228
+ logger_1.Logger.warning('当前没有配置');
229
+ logger_1.Logger.info('运行 ccs config add 添加配置');
230
+ return;
231
+ }
232
+ // 如果只有一个配置,显示详情
233
+ if (profiles.length === 1) {
234
+ const current = profiles[0];
235
+ const safeKey = current.apiKey.length > 12
236
+ ? `${current.apiKey.substring(0, 8)}...${current.apiKey.substring(current.apiKey.length - 4)}`
237
+ : '***';
238
+ console.log(chalk_1.default.cyan('\n📝 当前配置'));
239
+ console.log(chalk_1.default.gray('─'.repeat(70)));
240
+ console.log(chalk_1.default.white('配置名称: ') + chalk_1.default.green(current.name));
241
+ console.log(chalk_1.default.white('Base URL: ') + chalk_1.default.cyan(current.baseUrl));
242
+ console.log(chalk_1.default.white('API Key: ') + chalk_1.default.yellow(safeKey));
243
+ if (current.model) {
244
+ console.log(chalk_1.default.white('Model: ') + chalk_1.default.gray(current.model));
385
245
  }
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]);
246
+ if (current.smallFastModel) {
247
+ console.log(chalk_1.default.white('Small Fast Model: ') + chalk_1.default.gray(current.smallFastModel));
248
+ }
249
+ console.log(chalk_1.default.white('配置时间: ') + chalk_1.default.gray(new Date(current.configuredAt).toLocaleString('zh-CN')));
250
+ console.log(chalk_1.default.gray('─'.repeat(70)));
251
+ console.log(chalk_1.default.gray(`配置文件: ${config.getConfigPath()}\n`));
252
+ }
253
+ else {
254
+ // 多个配置时,显示提示
255
+ logger_1.Logger.info(`当前有 ${profiles.length} 个配置,启动时将提示选择`);
406
256
  console.log('');
407
- console.log(' 数据已提交上报');
257
+ console.log('使用 ccs config list 查看所有配置');
408
258
  console.log('');
409
- console.log('注: 上报结果请查看服务端日志');
259
+ }
260
+ return;
261
+ }
262
+ // config --reset - 重置所有配置
263
+ if (subArgs.includes('--reset')) {
264
+ if (!config.hasAnyProfile()) {
265
+ logger_1.Logger.warning('当前没有配置');
266
+ return;
267
+ }
268
+ const { confirm } = await inquirer_1.default.prompt([
269
+ {
270
+ type: 'confirm',
271
+ name: 'confirm',
272
+ message: chalk_1.default.red('⚠️ 确定要删除所有配置吗?此操作不可恢复!'),
273
+ default: false
274
+ }
275
+ ]);
276
+ if (!confirm) {
277
+ logger_1.Logger.info('已取消');
278
+ return;
279
+ }
280
+ config.reset();
281
+ logger_1.Logger.success('所有配置已重置');
282
+ logger_1.Logger.info('下次运行 ccs 时将重新配置');
283
+ console.log('');
284
+ return;
285
+ }
286
+ // config (无子命令) - 显示帮助或添加第一个配置
287
+ if (!subCommand) {
288
+ if (!config.hasAnyProfile()) {
289
+ // 如果没有配置,引导添加第一个配置
290
+ (0, welcome_1.showWelcome)();
291
+ const answers = await (0, prompts_1.showConfigPrompts)('default');
292
+ config.saveProfile(answers.name, {
293
+ apiKey: answers.apiKey,
294
+ baseUrl: answers.baseUrl,
295
+ model: answers.model,
296
+ smallFastModel: answers.smallFastModel
297
+ });
298
+ (0, welcome_1.showConfigSuccess)();
410
299
  console.log('');
411
- rl.close();
412
300
  }
413
- catch (error) {
301
+ else {
302
+ // 如果已有配置,显示配置管理帮助
303
+ console.log(chalk_1.default.cyan('\n⚙️ 配置管理\n'));
304
+ console.log('可用命令:');
414
305
  console.log('');
415
- console.log(' 上报失败:', error);
306
+ console.log(chalk_1.default.white(' ccs config list ') + chalk_1.default.gray('列出所有配置'));
307
+ console.log(chalk_1.default.white(' ccs config add ') + chalk_1.default.gray('添加新配置'));
308
+ console.log(chalk_1.default.white(' ccs config remove <名称> ') + chalk_1.default.gray('删除指定配置'));
309
+ console.log(chalk_1.default.white(' ccs config show ') + chalk_1.default.gray('显示当前配置'));
310
+ console.log(chalk_1.default.white(' ccs config --reset ') + chalk_1.default.gray('重置所有配置'));
416
311
  console.log('');
417
- rl.close();
418
312
  }
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)');
313
+ return;
314
+ }
315
+ // 未知子命令
316
+ logger_1.Logger.error(`未知的子命令: ${subCommand}`);
439
317
  console.log('');
440
- console.log('安装:');
441
- console.log(' npm install -g cc-code-status');
318
+ console.log('运行 ccs config 查看帮助');
442
319
  console.log('');
443
- console.log('安装后插件会自动配置。');
444
320
  }
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
- // 输出结果
321
+ /**
322
+ * 处理统计命令
323
+ */
324
+ async function handleStatsCommand(args) {
325
+ const subCommand = args[0] === 'stats' ? args[1] : args[0];
326
+ if (subCommand === 'week' || args[0] === 'week') {
327
+ // 引入旧版的 showWeekStats 函数
328
+ const { showWeekStats } = await Promise.resolve().then(() => __importStar(require('./cli-legacy')));
329
+ showWeekStats();
330
+ }
331
+ else if (subCommand === 'today') {
332
+ // 显示今日统计
333
+ const { StatusLinePlugin } = await Promise.resolve().then(() => __importStar(require('./index')));
334
+ const plugin = new StatusLinePlugin();
335
+ const stats = await plugin.getTodayStats();
500
336
  console.log('');
501
- console.log('========================================');
502
- console.log(` 本周统计 (${formatDate(weekStart)} 至 ${formatDate(weekEnd)})`);
503
- console.log('========================================');
337
+ console.log(chalk_1.default.cyan('📊 今日统计'));
504
338
  console.log('');
505
- console.log(`总计: ${totalConversations}次/${totalRounds}轮 | +${totalAdded}/-${totalDeleted} 行`);
339
+ console.log(`对话: ${stats.conversations}次/${stats.rounds}轮`);
340
+ console.log(`代码: +${stats.codeAdded}/-${stats.codeDeleted} 行`);
506
341
  console.log('');
507
- console.log('每日明细:');
342
+ }
343
+ else {
344
+ logger_1.Logger.error('未知的统计命令');
508
345
  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
- }
346
+ console.log('可用命令:');
347
+ console.log(' ccs stats today 显示今日统计');
348
+ console.log(' ccs stats week 显示本周统计');
514
349
  console.log('');
515
350
  }
516
- catch (error) {
517
- console.error('❌ 统计失败:', error);
351
+ }
352
+ /**
353
+ * 处理同步命令
354
+ */
355
+ async function handleSyncCommand(args) {
356
+ const command = args[0];
357
+ // 引入旧版的同步函数
358
+ const { setSyncEnabled, showSyncStatus, manualSync, customSync } = await Promise.resolve().then(() => __importStar(require('./cli-legacy')));
359
+ if (command === 'sync-enable') {
360
+ setSyncEnabled(true);
361
+ }
362
+ else if (command === 'sync-disable') {
363
+ setSyncEnabled(false);
364
+ }
365
+ else if (command === 'sync-status') {
366
+ showSyncStatus();
367
+ }
368
+ else if (command === 'sync-now' || command === 'sync') {
369
+ await manualSync();
370
+ }
371
+ else if (command === 'custom-sync') {
372
+ await customSync();
518
373
  }
519
374
  }
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}`;
375
+ /**
376
+ * 处理排除命令
377
+ */
378
+ async function handleExcludeCommand(subArgs) {
379
+ const { handleExclude } = await Promise.resolve().then(() => __importStar(require('./cli-legacy')));
380
+ handleExclude(subArgs);
526
381
  }
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
- }
382
+ /**
383
+ * 处理 setup 命令(旧版兼容)
384
+ */
385
+ async function handleSetup() {
386
+ const { setup } = await Promise.resolve().then(() => __importStar(require('./cli-legacy')));
387
+ setup();
388
+ }
389
+ /**
390
+ * 处理 uninstall 命令(旧版兼容)
391
+ */
392
+ async function handleUninstall() {
393
+ const { uninstall } = await Promise.resolve().then(() => __importStar(require('./cli-legacy')));
394
+ uninstall();
395
+ }
396
+ /**
397
+ * 作为状态栏插件运行
398
+ */
399
+ async function runAsStatusLine() {
400
+ const { StatusLinePlugin } = await Promise.resolve().then(() => __importStar(require('./index')));
401
+ const plugin = new StatusLinePlugin();
402
+ await plugin.run().catch(() => {
403
+ console.log('Error');
404
+ });
405
+ }
406
+ /**
407
+ * 作为启动器运行
408
+ */
409
+ async function runAsLauncher(args) {
410
+ const config = new manager_1.ConfigManager();
411
+ // 检查是否有配置
412
+ if (!config.hasAnyProfile()) {
413
+ console.log('');
414
+ logger_1.Logger.info('首次使用需要配置 API');
415
+ console.log('');
416
+ // 显示欢迎信息
417
+ (0, welcome_1.showWelcome)();
418
+ // 交互式配置
419
+ const answers = await (0, prompts_1.showConfigPrompts)('default');
420
+ // 保存配置
421
+ config.saveProfile(answers.name, {
422
+ apiKey: answers.apiKey,
423
+ baseUrl: answers.baseUrl,
424
+ model: answers.model,
425
+ smallFastModel: answers.smallFastModel
426
+ });
427
+ // 显示成功信息
428
+ (0, welcome_1.showConfigSuccess)();
429
+ // 短暂延迟
430
+ await new Promise(resolve => setTimeout(resolve, 1000));
431
+ }
432
+ // 如果有配置,检查是否需要选择配置
433
+ let selectedProfileName;
434
+ if (config.hasAnyProfile()) {
435
+ // 如果有多个配置,需要用户选择
436
+ const profileCount = config.getProfileCount();
437
+ // 检查命令行参数中是否指定了配置
438
+ const profileArgIndex = args.findIndex(arg => arg === '--profile' || arg === '-p');
439
+ if (profileArgIndex !== -1 && args[profileArgIndex + 1]) {
440
+ // 通过命令行参数指定配置
441
+ selectedProfileName = args[profileArgIndex + 1];
442
+ if (!config.hasProfile(selectedProfileName)) {
443
+ logger_1.Logger.error(`配置 "${selectedProfileName}" 不存在`);
444
+ console.log('');
445
+ console.log('使用 ccs config list 查看所有配置');
446
+ console.log('');
447
+ process.exit(1);
561
448
  }
449
+ // 移除 --profile 参数(避免传递给 Claude)
450
+ args.splice(profileArgIndex, 2);
451
+ }
452
+ else if (profileCount > 1) {
453
+ // 如果有多个配置,让用户选择
454
+ const profiles = config.getAllProfiles().map(p => ({
455
+ name: p.name,
456
+ config: p
457
+ }));
458
+ console.log('');
459
+ logger_1.Logger.info('检测到多个配置,请选择要使用的配置');
460
+ console.log('');
461
+ selectedProfileName = await (0, prompts_1.selectProfile)(profiles);
462
+ console.log('');
463
+ logger_1.Logger.success(`已选择配置: ${selectedProfileName}`);
464
+ console.log('');
465
+ // 短暂延迟
466
+ await new Promise(resolve => setTimeout(resolve, 500));
562
467
  }
563
- return sessionIds.size;
564
468
  }
565
- catch {
566
- return 0;
469
+ // 检查 Claude Code 是否已安装
470
+ if (!(0, installer_1.checkClaudeInstallation)()) {
471
+ process.exit(1);
567
472
  }
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;
473
+ // 显示当前使用的配置
474
+ let displayProfile;
475
+ if (selectedProfileName) {
476
+ // 使用选中的配置
477
+ const profile = config.getProfile(selectedProfileName);
478
+ if (profile) {
479
+ displayProfile = { name: selectedProfileName, baseUrl: profile.baseUrl };
574
480
  }
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
481
  }
596
- catch {
597
- return 0;
482
+ else {
483
+ // 使用唯一配置
484
+ const current = config.getCurrentProfile();
485
+ if (current) {
486
+ displayProfile = { name: current.name, baseUrl: current.config.baseUrl };
487
+ }
598
488
  }
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 };
489
+ if (displayProfile) {
490
+ // baseUrl 提取域名
491
+ let domain = displayProfile.baseUrl;
492
+ try {
493
+ const url = new URL(displayProfile.baseUrl);
494
+ domain = url.hostname;
605
495
  }
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
- }
496
+ catch (e) {
497
+ // 如果不是有效 URL,使用原始值
654
498
  }
655
- return { added, deleted };
656
- }
657
- catch {
658
- return { added: 0, deleted: 0 };
499
+ console.log(chalk_1.default.gray(`使用配置: ${displayProfile.name} (${domain})\n`));
659
500
  }
501
+ // 启动 Claude Code
502
+ const launcher = new launcher_1.ClaudeLauncher(config, selectedProfileName);
503
+ const { exitCode } = await launcher.launch({
504
+ args,
505
+ skipPermissions: true,
506
+ showStats: true
507
+ });
508
+ process.exit(exitCode);
509
+ }
510
+ // 运行主函数
511
+ if (require.main === module) {
512
+ main();
660
513
  }
661
514
  //# sourceMappingURL=cli.js.map