g2log 1.4.0 → 1.4.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 (3) hide show
  1. package/README.md +13 -5
  2. package/git-user-log.js +119 -163
  3. package/package.json +5 -2
package/README.md CHANGED
@@ -66,13 +66,20 @@ npx g2log [--since="2023-01-01"] [--until="2023-12-31"] [选项]
66
66
 
67
67
  ### 命令行参数
68
68
 
69
+ 时间参数:
69
70
  - `--since="YYYY-MM-DD"` - 起始日期(如未指定,使用配置中的默认值)
70
71
  - `--until="YYYY-MM-DD"` - 结束日期(如未指定,使用配置中的默认值)
71
- - `--local` - 使用本地仓库,忽略配置文件中的仓库设置
72
- - `--output="文件路径"` - 将输出保存到指定文件
72
+ - `--days=N` - 查询最近N天的记录
73
73
 
74
- ### 配置管理命令
74
+ 显示设置:
75
+ - `--no-color` - 禁用彩色输出
76
+ - `--save` 或 `--output="文件路径"` - 将输出保存到文件
77
+ - `--debug` - 显示调试信息
78
+ - `--show-prompt` - 显示完整的prompt内容
79
+ - `--version` - 显示当前版本号
75
80
 
81
+ 配置管理命令:
82
+ - `--config` - 启动交互式配置向导
76
83
  - `--set-api-key="KEY"` - 设置API密钥
77
84
  - `--set-ai-model="MODEL"` - 设置AI模型(默认: deepseek-chat)
78
85
  - `--set-api-provider="PROVIDER"` - 设置API提供商(deepseek或openai)
@@ -85,6 +92,7 @@ npx g2log [--since="2023-01-01"] [--until="2023-12-31"] [选项]
85
92
  - `--set-prompt-template="file.txt"` - 从文件设置AI总结的prompt模板
86
93
  - `--reset-prompt-template` - 重置AI总结的prompt模板为默认值
87
94
  - `--fix-config` - 修复配置文件格式问题
95
+ - `--uninstall` - 删除g2log配置文件
88
96
  - `--help` - 显示帮助信息
89
97
 
90
98
  ### 配置文件
@@ -95,7 +103,7 @@ npx g2log [--since="2023-01-01"] [--until="2023-12-31"] [选项]
95
103
  {
96
104
  "api_key": "your-api-key-here",
97
105
  "default_author": "张三",
98
- "default_since": "today",
106
+ "default_since": "7 days ago",
99
107
  "default_until": "today",
100
108
  "model": "deepseek-chat",
101
109
  "api_base_url": "https://api.deepseek.com",
@@ -104,7 +112,7 @@ npx g2log [--since="2023-01-01"] [--until="2023-12-31"] [选项]
104
112
  "前端": "/path/to/frontend-project",
105
113
  "后端": "/path/to/backend-project"
106
114
  },
107
- "prompt_template": "请根据下面的Git提交记录,用3-5句话简洁地总结一天的工作内容..."
115
+ "prompt_template": "请根据下面的Git提交记录,用3-5句话简洁地总结一天的工作内容。\n\n以下是Git提交记录:\n\n{{GIT_LOGS}}\n\n要求:\n1. 按项目和日期组织内容\n2. 每个项目每天的工作内容用3-5句话概括\n3. 使用清晰、专业但不晦涩的语言\n4. 突出重要的功能开发、问题修复和优化改进\n5. 适合放入工作日报的简洁描述\n6. 输出格式为:【日期】:\n 【项目名称】- 【工作内容概述】\n 【项目名称】- 【工作内容概述】\n7. 回复不要出现多余的内容,非必要不要用markdown格式"
108
116
  }
109
117
  ```
110
118
 
package/git-user-log.js CHANGED
@@ -17,6 +17,7 @@ const fs = require('fs');
17
17
  const https = require('https');
18
18
  const os = require('os');
19
19
  const readline = require('readline');
20
+ const ora = require('ora');
20
21
 
21
22
  // 检测是否通过npx运行
22
23
  const isRunningWithNpx = process.env.npm_lifecycle_event === 'npx' ||
@@ -375,63 +376,41 @@ function fixConfigFile() {
375
376
  // 显示帮助
376
377
  function showHelp() {
377
378
  console.log(`
378
- ${colorize('✨ 获取指定用户和时间范围的Git日志 ✨', 'bright')}
379
-
380
- ${colorize('📋 使用方法:', 'yellow')}
381
- g2log [--since="2023-01-01"] [--until="2023-12-31"] [选项]
382
-
383
- ${colorize('🕒 时间参数:', 'green')}
384
- --since="YYYY-MM-DD" 起始日期 (如未指定,使用配置文件中的默认值)
385
- --until="YYYY-MM-DD" 结束日期 (如未指定,使用配置文件中的默认值)
386
- --local 使用本地仓库,忽略配置文件中的仓库设置
387
-
388
- ${colorize('🎨 显示设置:', 'blue')}
389
- --color, --force-color 强制启用彩色输出 (即使在管道或重定向中)
390
- --no-color 禁用彩色输出
391
- --nosave 不保存到文件 (仅在终端显示)
392
- --save="file.txt" 保存结果到指定文件
393
- --debug, --show-prompt 显示发送给AI的完整提示内容
394
-
395
- ${colorize('⚙️ 配置管理:', 'magenta')}
396
- --config 启动交互式配置向导
397
- --skip-config-check 跳过配置检查
398
- --set-api-key="KEY" 设置API密钥
399
- --set-api-provider="PROVIDER" 设置API提供商 (deepseek或openai)
400
- --set-api-url="URL" 设置API基础URL
401
- --set-ai-model="MODEL" 设置AI模型 (默认: deepseek-chat,可选: deepseek-reasoner)
402
- --set-default-author="NAME" 设置默认作者
403
- --set-time-range --since="DATE" --until="DATE" 设置默认时间范围
404
- --add-repo="ALIAS" --path="/path/to/repo" 添加仓库配置
405
- --remove-repo="ALIAS" 删除仓库配置
406
- --list-repos 列出所有配置的仓库
407
- --set-prompt-template="file.txt" 从文件设置AI总结的prompt模板
408
- --reset-prompt-template 重置AI总结的prompt模板为默认值
409
- --fix-config 修复配置文件格式问题
410
- --uninstall 删除g2log配置文件 (~/.git-user-log-config.json)
411
- --help 显示帮助信息
412
-
413
- ${colorize('📝 示例:', 'cyan')}
414
- # 使用配置的默认值生成今日工作总结 (处理配置中的所有仓库)
415
- g2log
416
-
417
- # 指定时间范围
418
- g2log --since="2023-01-01" --until="2023-12-31"
419
-
420
- # 使用本地仓库
421
- g2log --local
422
-
423
- # 强制启用颜色显示(在使用管道或重定向时有用)
424
- g2log --color | less -R
425
-
426
- # 启动交互式配置向导
379
+ 使用方法: g2log [选项]
380
+
381
+ 时间参数:
382
+ --since <date> 开始日期 (默认: 7天前)
383
+ --until <date> 结束日期 (默认: 今天)
384
+ --days <number> 查询最近n天的记录 (默认: 7)
385
+
386
+ 显示设置:
387
+ --no-color 禁用彩色输出
388
+ --save 保存结果到文件
389
+ --debug 显示调试信息
390
+ --show-prompt 显示完整的prompt内容
391
+ --version 显示当前版本号
392
+
393
+ 配置管理:
394
+ --config 启动交互式配置向导
395
+ --set-api-key 设置API密钥
396
+ --set-api-provider 设置API提供商 (OpenAI/DeepSeek)
397
+ --set-api-base-url 设置API基础URL
398
+ --set-ai-model 设置AI模型
399
+ --set-default-author 设置默认作者
400
+ --add-repo 添加仓库配置
401
+ --remove-repo 移除仓库配置
402
+ --list-repos 列出所有配置的仓库
403
+ --uninstall 删除g2log配置文件 (~/.git-user-log-config.json)
404
+
405
+ 示例:
406
+ g2log --since "2024-01-01" --until "2024-01-31"
407
+ g2log --days 30
427
408
  g2log --config
428
-
429
- # 设置配置
430
- g2log --set-default-author="张三"
431
- g2log --set-ai-model="deepseek-reasoner"
432
- g2log --set-api-provider="openai"
433
- g2log --set-api-url="https://api.openai.com"
434
- g2log --add-repo="frontend" --path="/path/to/frontend-project"
409
+ g2log --set-api-key "your-api-key"
410
+ g2log --add-repo "alias" "path/to/repo"
411
+ g2log --remove-repo "alias"
412
+ g2log --list-repos
413
+ g2log --version
435
414
  `);
436
415
  process.exit(0);
437
416
  }
@@ -697,6 +676,12 @@ Git提交记录:
697
676
  let aiResponse = '';
698
677
  const providerLower = apiProvider.toLowerCase();
699
678
 
679
+ // 输出AI总结的标题信息
680
+ console.log(`\n${colorize('📊 ' + author + ' 的工作总结', 'bright')}`);
681
+ console.log(`${colorize('📅 时间范围: ' + since + ' 至 ' + until, 'green')}`);
682
+ console.log(`${colorize('🤖 使用模型: ' + modelName, 'cyan')}`);
683
+ console.log(`${colorize('=' .repeat(30), 'bright')}\n`);
684
+
700
685
  // 根据提供商名称选择对应的实现
701
686
  if (providerLower === 'openai') {
702
687
  aiResponse = await getOpenAIResponse(apiKey, prompt, modelName, apiBaseURL, spinner);
@@ -708,43 +693,6 @@ Git提交记录:
708
693
  // 停止spinner并显示成功消息
709
694
  if (spinner) spinner.stop('✅ AI总结已生成');
710
695
 
711
- // 格式化并输出AI总结
712
- console.log(`\n${colorize('📊 ' + author + ' 的工作总结', 'bright')}`);
713
- console.log(`${colorize('📅 时间范围: ' + since + ' 至 ' + until, 'green')}`);
714
- console.log(`${colorize('🤖 使用模型: ' + modelName, 'cyan')}`);
715
- console.log(`${colorize('=' .repeat(30), 'bright')}\n`);
716
-
717
- // 分段输出并优化格式
718
- const lines = aiResponse.split('\n');
719
- for (let i = 0; i < lines.length; i++) {
720
- const line = lines[i];
721
-
722
- // 为标题添加颜色
723
- if (line.startsWith('# ')) {
724
- console.log(colorize(line, 'bright'));
725
- }
726
- // 为子标题添加颜色
727
- else if (line.startsWith('## ')) {
728
- console.log(colorize(line, 'yellow'));
729
- }
730
- // 为列表项添加图标和颜色
731
- else if (line.trim().startsWith('- ')) {
732
- console.log(colorize(' • ' + line.trim().substring(2), 'reset'));
733
- }
734
- // 为数字列表添加颜色
735
- else if (/^\d+\.\s/.test(line.trim())) {
736
- console.log(colorize(' ' + line.trim(), 'reset'));
737
- }
738
- // 为分隔线添加颜色
739
- else if (line.trim().startsWith('---')) {
740
- console.log(colorize(' ' + '─'.repeat(30), 'dim'));
741
- }
742
- // 普通文本
743
- else {
744
- console.log(colorize(line, 'reset'));
745
- }
746
- }
747
-
748
696
  return aiResponse;
749
697
  } catch (error) {
750
698
  if (spinner) spinner.fail(`❌ AI总结失败: ${error.message}`);
@@ -779,7 +727,7 @@ async function getOpenAIResponse(apiKey, prompt, modelName, apiBaseURL, spinner
779
727
  };
780
728
 
781
729
  // 打印请求内容
782
- console.log(colorize('\n📨 发送给OpenAI的请求:', 'cyan'));
730
+ console.log(colorize('\n📨 发送给AI的请求:', 'cyan'));
783
731
  console.log(colorize(`📌 API端点: ${url}`, 'dim'));
784
732
  console.log(colorize(`🤖 使用模型: ${data.model}`, 'dim'));
785
733
  console.log(colorize(`🌡️ 温度: ${data.temperature}`, 'dim'));
@@ -787,7 +735,7 @@ async function getOpenAIResponse(apiKey, prompt, modelName, apiBaseURL, spinner
787
735
  console.log(colorize('📄 系统角色: ' + data.messages[0].content, 'dim'));
788
736
  console.log(colorize('💬 提示内容预览: ' + data.messages[1].content.substring(0, 150) + '...', 'dim'));
789
737
 
790
- if (spinner) spinner.update('🔄 正在向OpenAI发送请求...');
738
+ if (spinner) spinner.update('🔄 正在向AI发送请求...\n');
791
739
 
792
740
  return new Promise((resolve, reject) => {
793
741
  try {
@@ -805,54 +753,54 @@ async function getOpenAIResponse(apiKey, prompt, modelName, apiBaseURL, spinner
805
753
 
806
754
  // 确定使用http还是https
807
755
  const protocol = urlObj.protocol === 'https:' ? require('https') : require('http');
808
-
809
- // 创建请求
810
- const req = protocol.request(options, (res) => {
756
+
757
+ // 创建请求
758
+ const req = protocol.request(options, (res) => {
811
759
  // 检查状态码
812
- if (res.statusCode !== 200) {
813
- let errorData = '';
814
- res.on('data', chunk => {
815
- errorData += chunk.toString();
816
- });
817
- res.on('end', () => {
760
+ if (res.statusCode !== 200) {
761
+ let errorData = '';
762
+ res.on('data', chunk => {
763
+ errorData += chunk.toString();
764
+ });
765
+ res.on('end', () => {
818
766
  let errorMessage = `OpenAI API请求失败 (${res.statusCode})`;
819
- try {
820
- const parsedError = JSON.parse(errorData);
767
+ try {
768
+ const parsedError = JSON.parse(errorData);
821
769
  errorMessage += `: ${JSON.stringify(parsedError)}`;
822
- } catch (e) {
770
+ } catch (e) {
823
771
  errorMessage += `: ${errorData}`;
824
772
  }
825
773
  if (spinner) spinner.fail(`❌ ${errorMessage}`);
826
774
  reject(new Error(errorMessage));
827
- });
828
- return;
829
- }
830
-
775
+ });
776
+ return;
777
+ }
778
+
831
779
  let fullContent = '';
832
- let buffer = '';
833
-
780
+ let buffer = '';
781
+
834
782
  // 处理数据
835
- res.on('data', (chunk) => {
836
- // 将新的数据添加到缓冲区
837
- buffer += chunk.toString();
783
+ res.on('data', (chunk) => {
784
+ // 将新的数据添加到缓冲区
785
+ buffer += chunk.toString();
786
+
787
+ // 尝试从缓冲区中提取完整的SSE消息
788
+ let match;
789
+ const dataRegex = /data: (.*?)\n\n/gs;
790
+
791
+ while ((match = dataRegex.exec(buffer)) !== null) {
792
+ const data = match[1];
838
793
 
839
- // 尝试从缓冲区中提取完整的SSE消息
840
- let match;
841
- const dataRegex = /data: (.*?)\n\n/gs;
794
+ // 跳过 [DONE] 消息
795
+ if (data === '[DONE]') continue;
842
796
 
843
- while ((match = dataRegex.exec(buffer)) !== null) {
844
- const data = match[1];
797
+ try {
798
+ const parsedData = JSON.parse(data);
845
799
 
846
- // 跳过 [DONE] 消息
847
- if (data === '[DONE]') continue;
848
-
849
- try {
850
- const parsedData = JSON.parse(data);
851
-
852
800
  // 获取内容增量
853
801
  if (parsedData.choices &&
854
- parsedData.choices[0] &&
855
- parsedData.choices[0].delta &&
802
+ parsedData.choices[0] &&
803
+ parsedData.choices[0].delta &&
856
804
  parsedData.choices[0].delta.content) {
857
805
  const content = parsedData.choices[0].delta.content;
858
806
  fullContent += content;
@@ -874,7 +822,7 @@ async function getOpenAIResponse(apiKey, prompt, modelName, apiBaseURL, spinner
874
822
 
875
823
  // 处理结束
876
824
  res.on('end', () => {
877
- if (spinner) spinner.stop('✅ OpenAI响应已接收');
825
+ if (spinner) spinner.stop('✅ AI响应已结束');
878
826
  console.log(); // 添加换行符
879
827
  resolve(fullContent);
880
828
  });
@@ -1003,27 +951,27 @@ async function getDeepSeekResponse(apiKey, prompt, modelName, apiBaseURL, spinne
1003
951
 
1004
952
  // 直接输出内容增量到控制台
1005
953
  process.stdout.write(content);
1006
- }
1007
- } catch (err) {
1008
- // 忽略解析错误
1009
954
  }
955
+ } catch (err) {
956
+ // 忽略解析错误
1010
957
  }
1011
-
1012
- // 保留可能不完整的最后一部分
1013
- const lastIndex = buffer.lastIndexOf('\n\n');
1014
- if (lastIndex !== -1) {
1015
- buffer = buffer.substring(lastIndex + 2);
1016
- }
1017
- });
958
+ }
1018
959
 
960
+ // 保留可能不完整的最后一部分
961
+ const lastIndex = buffer.lastIndexOf('\n\n');
962
+ if (lastIndex !== -1) {
963
+ buffer = buffer.substring(lastIndex + 2);
964
+ }
965
+ });
966
+
1019
967
  // 处理结束
1020
- res.on('end', () => {
968
+ res.on('end', () => {
1021
969
  if (spinner) spinner.stop('✅ AI响应已接收');
1022
970
  console.log(); // 添加换行符
1023
971
  resolve(fullContent);
1024
- });
1025
972
  });
1026
-
973
+ });
974
+
1027
975
  // 处理请求错误
1028
976
  req.on('error', (error) => {
1029
977
  if (spinner) spinner.fail(`❌ DeepSeek API网络错误: ${error.message}`);
@@ -1032,7 +980,7 @@ async function getDeepSeekResponse(apiKey, prompt, modelName, apiBaseURL, spinne
1032
980
 
1033
981
  // 发送请求体
1034
982
  req.write(JSON.stringify(data));
1035
- req.end();
983
+ req.end();
1036
984
  } catch (error) {
1037
985
  if (spinner) spinner.fail(`❌ DeepSeek API错误: ${error.message}`);
1038
986
  reject(error);
@@ -1488,15 +1436,35 @@ async function setupConfigInteractive() {
1488
1436
 
1489
1437
  // 主函数
1490
1438
  async function getGitLogs() {
1439
+ const args = parseArgs();
1440
+
1441
+ // 显示帮助信息
1442
+ if (args['help']) {
1443
+ showHelp();
1444
+ return;
1445
+ }
1446
+
1447
+ // 显示版本信息
1448
+ if (args['version']) {
1449
+ const packageJson = require('./package.json');
1450
+ console.log(`g2log version ${packageJson.version}`);
1451
+ return;
1452
+ }
1453
+
1454
+ // 删除配置文件
1455
+ if (args['uninstall']) {
1456
+ const spinner = ora('正在删除配置文件...').start();
1457
+ const success = removeConfigFile();
1458
+ if (success) {
1459
+ spinner.succeed('配置文件已删除,如需完全卸载请运行: npm uninstall -g g2log');
1460
+ } else {
1461
+ spinner.fail('配置文件删除失败,可能文件不存在或无权限访问');
1462
+ }
1463
+ return;
1464
+ }
1465
+
1491
1466
  try {
1492
1467
  const spinner = createSpinner();
1493
- const args = parseArgs();
1494
-
1495
- // 显示帮助信息
1496
- if (args.help) {
1497
- showHelp();
1498
- return;
1499
- }
1500
1468
 
1501
1469
  // 检查是否要显示自定义配置向导
1502
1470
  if (args.config) {
@@ -1562,18 +1530,6 @@ async function getGitLogs() {
1562
1530
  // 加载配置(在配置检查和可能的设置之后)
1563
1531
  const config = loadConfig();
1564
1532
 
1565
- // 删除配置文件
1566
- if (args['uninstall']) {
1567
- const uninstallSpinner = spinner.start('🗑️ 正在删除g2log配置文件...');
1568
- if (removeConfigFile()) {
1569
- uninstallSpinner.stop('✅ g2log配置文件已成功删除');
1570
- console.log(colorize('💡 提示: 如需完全卸载g2log,还需执行 npm uninstall -g g2log', 'yellow'));
1571
- } else {
1572
- uninstallSpinner.fail('❌ 配置文件不存在或删除失败');
1573
- }
1574
- return;
1575
- }
1576
-
1577
1533
  // 修复配置文件
1578
1534
  if (args['fix-config']) {
1579
1535
  const fixSpinner = spinner.start('🔧 正在修复配置文件...');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "g2log",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "查询特定用户和时间范围的Git提交记录并通过AI进行总结,可通过npx直接运行",
5
5
  "main": "git-user-log.js",
6
6
  "bin": {
@@ -34,5 +34,8 @@
34
34
  "bugs": {
35
35
  "url": "https://github.com/chenxiangcai/git-user-log/issues"
36
36
  },
37
- "homepage": "https://github.com/chenxiangcai/git-user-log#readme"
37
+ "homepage": "https://github.com/chenxiangcai/git-user-log#readme",
38
+ "dependencies": {
39
+ "ora": "^8.2.0"
40
+ }
38
41
  }