g2log 1.4.5 → 1.5.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/.claude/settings.local.json +7 -0
- package/CLAUDE.md +169 -0
- package/git-user-log.js +87 -87
- package/package.json +2 -2
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
`g2log` (AI-Git 用户日报生成工具) is a Node.js CLI tool that retrieves Git commit records for specified users within a time range and automatically generates work summaries using AI. It can be run via `npx` without installation or installed globally.
|
|
8
|
+
|
|
9
|
+
## Common Commands
|
|
10
|
+
|
|
11
|
+
### Installation and Setup
|
|
12
|
+
```bash
|
|
13
|
+
# Global installation
|
|
14
|
+
npm install -g g2log
|
|
15
|
+
|
|
16
|
+
# Run via npx (no installation needed)
|
|
17
|
+
npx g2log [options]
|
|
18
|
+
|
|
19
|
+
# Direct execution
|
|
20
|
+
node git-user-log.js
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Configuration Management
|
|
24
|
+
```bash
|
|
25
|
+
# Start interactive configuration wizard
|
|
26
|
+
g2log --config
|
|
27
|
+
|
|
28
|
+
# Set API key for AI summarization
|
|
29
|
+
g2log --set-api-key="YOUR_API_KEY"
|
|
30
|
+
|
|
31
|
+
# Set default author name
|
|
32
|
+
g2log --set-default-author="作者名"
|
|
33
|
+
|
|
34
|
+
# Add repository configuration
|
|
35
|
+
g2log --add-repo="别名" --path="/path/to/repo"
|
|
36
|
+
|
|
37
|
+
# List configured repositories
|
|
38
|
+
g2log --list-repos
|
|
39
|
+
|
|
40
|
+
# Fix configuration file format issues
|
|
41
|
+
g2log --fix-config
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Running the Tool
|
|
45
|
+
```bash
|
|
46
|
+
# Generate daily summary using defaults
|
|
47
|
+
g2log
|
|
48
|
+
|
|
49
|
+
# Specify time range
|
|
50
|
+
g2log --since="2023-01-01" --until="2023-12-31"
|
|
51
|
+
|
|
52
|
+
# Use local repository only
|
|
53
|
+
g2log --local
|
|
54
|
+
|
|
55
|
+
# Save output to file
|
|
56
|
+
g2log --output="today-summary.md"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Architecture
|
|
60
|
+
|
|
61
|
+
### Entry Point and Core Structure
|
|
62
|
+
|
|
63
|
+
- **`git-user-log.js`** - Main CLI entry point (executable, ~1940 lines)
|
|
64
|
+
- Single-file architecture with all functionality inline
|
|
65
|
+
- Uses ES modules via dynamic `import()` for the `ora` spinner library
|
|
66
|
+
- No build process or transpilation required
|
|
67
|
+
|
|
68
|
+
### Key Components
|
|
69
|
+
|
|
70
|
+
1. **Configuration System** (`CONFIG_PATH = ~/.git-user-log-config.json`)
|
|
71
|
+
- `loadConfig()` - Merges user config with `DEFAULT_CONFIG`
|
|
72
|
+
- `saveConfig()` - Persists configuration
|
|
73
|
+
- Handles legacy field migrations (e.g., `deepseek_api_key` → `api_key`)
|
|
74
|
+
- Supports prompt template customization with variable substitution
|
|
75
|
+
|
|
76
|
+
2. **Git Log Retrieval**
|
|
77
|
+
- Single repository: Uses `git -C "{path}" log` with author/time filters
|
|
78
|
+
- Multi-repository: `getLogsFromMultipleRepos()` aggregates from all configured repos
|
|
79
|
+
- Format: `alias | date | hash | message` or simple mode without hash
|
|
80
|
+
|
|
81
|
+
3. **AI Integration**
|
|
82
|
+
- `summarizeWithAI()` - Main orchestrator
|
|
83
|
+
- `getOpenAIResponse()` - OpenAI API with streaming support
|
|
84
|
+
- `getDeepSeekResponse()` - DeepSeek API with streaming support
|
|
85
|
+
- Both use Server-Sent Events (SSE) for real-time output streaming
|
|
86
|
+
|
|
87
|
+
4. **Interactive Configuration Wizard**
|
|
88
|
+
- `setupConfigInteractive()` - Step-by-step CLI prompts
|
|
89
|
+
- Uses Node.js `readline` module for user input
|
|
90
|
+
- Validates Git repository paths before adding
|
|
91
|
+
|
|
92
|
+
### Configuration File Structure
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"api_key": "sk-...",
|
|
97
|
+
"default_author": "用户名",
|
|
98
|
+
"default_since": "today",
|
|
99
|
+
"default_until": "today",
|
|
100
|
+
"model": "deepseek-chat",
|
|
101
|
+
"api_base_url": "https://api.deepseek.com",
|
|
102
|
+
"api_provider": "deepseek",
|
|
103
|
+
"repositories": {
|
|
104
|
+
"别名": "/path/to/repo"
|
|
105
|
+
},
|
|
106
|
+
"prompt_template": "自定义提示词模板,支持 {{GIT_LOGS}} 等变量"
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### CLI Argument Parsing
|
|
111
|
+
|
|
112
|
+
Custom `parseArgs()` function handles:
|
|
113
|
+
- `--key=value` format
|
|
114
|
+
- `--key value` format
|
|
115
|
+
- Boolean flags like `--local`, `--no-color`
|
|
116
|
+
- Special handling for `--save` as alias for `--output`
|
|
117
|
+
|
|
118
|
+
### Color Output System
|
|
119
|
+
|
|
120
|
+
Custom ANSI color implementation:
|
|
121
|
+
- Pre-checks for TTY and `--no-color` flag
|
|
122
|
+
- `colorize()` function wraps text with ANSI codes
|
|
123
|
+
- Custom `createSpinner()` with fallback when `ora` fails to load
|
|
124
|
+
|
|
125
|
+
## Development Notes
|
|
126
|
+
|
|
127
|
+
### Dynamic Import Pattern
|
|
128
|
+
|
|
129
|
+
The `ora` module is loaded dynamically to handle potential import failures:
|
|
130
|
+
```javascript
|
|
131
|
+
let ora;
|
|
132
|
+
import('ora').then(module => { ora = module.default; }).catch(...);
|
|
133
|
+
```
|
|
134
|
+
The spinner function checks if `ora` is loaded and provides a fallback.
|
|
135
|
+
|
|
136
|
+
### Streaming Response Handling
|
|
137
|
+
|
|
138
|
+
Both `getOpenAIResponse()` and `getDeepSeekResponse()` implement SSE parsing:
|
|
139
|
+
- Buffer incomplete messages
|
|
140
|
+
- Split by `\n\n` delimiter
|
|
141
|
+
- Parse `data: {json}` lines
|
|
142
|
+
- Handle `[DONE]` termination signal
|
|
143
|
+
|
|
144
|
+
### Variable Substitution in Prompts
|
|
145
|
+
|
|
146
|
+
The `prompt_template` supports multiple variable formats for compatibility:
|
|
147
|
+
- `{{GIT_LOGS}}` and `{log_content}` for git logs
|
|
148
|
+
- `{{AUTHOR}}` and `{author}` for author name
|
|
149
|
+
- `{{SINCE}}`/`{{UNTIL}}` and `{since}`/`{until}` for dates
|
|
150
|
+
|
|
151
|
+
### NPX Detection
|
|
152
|
+
|
|
153
|
+
The tool detects NPX execution via environment variables:
|
|
154
|
+
```javascript
|
|
155
|
+
const isRunningWithNpx = process.env.npm_lifecycle_event === 'npx' ||
|
|
156
|
+
process.env.npm_execpath?.includes('npx') ||
|
|
157
|
+
process.env.npm_command === 'exec';
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Version and Publishing
|
|
161
|
+
|
|
162
|
+
- Version is defined in `package.json` (currently 1.4.4)
|
|
163
|
+
- See `PUBLISH.md` for publishing workflow to npm
|
|
164
|
+
- Postinstall script sets executable permissions on `git-user-log.js`
|
|
165
|
+
|
|
166
|
+
## Dependencies
|
|
167
|
+
|
|
168
|
+
- **ora** - CLI spinner for loading states (dynamically imported)
|
|
169
|
+
- **No build tools** - Pure Node.js with standard library modules
|
package/git-user-log.js
CHANGED
|
@@ -77,7 +77,6 @@ function colorize(text, color) {
|
|
|
77
77
|
|
|
78
78
|
// 配置文件路径
|
|
79
79
|
const CONFIG_PATH = path.join(os.homedir(), '.git-user-log-config.json');
|
|
80
|
-
console.log(CONFIG_PATH);
|
|
81
80
|
// 默认配置
|
|
82
81
|
const DEFAULT_CONFIG = {
|
|
83
82
|
api_key: '',
|
|
@@ -89,21 +88,21 @@ const DEFAULT_CONFIG = {
|
|
|
89
88
|
api_provider: 'deepseek', // API提供商: deepseek或openai
|
|
90
89
|
repositories: {},
|
|
91
90
|
prompt_template: `
|
|
92
|
-
请根据下面的Git提交记录,用3-5
|
|
91
|
+
请根据下面的Git提交记录,用3-5句话简洁地总结工作内容。
|
|
93
92
|
|
|
94
93
|
以下是Git提交记录:
|
|
95
94
|
|
|
96
95
|
{{GIT_LOGS}}
|
|
97
96
|
|
|
98
97
|
要求:
|
|
99
|
-
1.
|
|
100
|
-
2.
|
|
98
|
+
1. 按项目、日期和作者组织内容
|
|
99
|
+
2. 每个项目每天每个作者的工作内容用3-5句话概括
|
|
101
100
|
3. 使用清晰、专业但不晦涩的语言
|
|
102
101
|
4. 突出重要的功能开发、问题修复和优化改进
|
|
103
102
|
5. 适合放入工作日报的简洁描述
|
|
104
103
|
6. 输出格式为:【日期】:
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
【项目名称】 - 【作者】 - 【工作内容概述】
|
|
105
|
+
【项目名称】 - 【作者】 - 【工作内容概述】
|
|
107
106
|
7. 回复不要出现多余的内容,非必要不要用markdown格式
|
|
108
107
|
`
|
|
109
108
|
};
|
|
@@ -416,32 +415,38 @@ function showHelp() {
|
|
|
416
415
|
--until <date> 结束日期 (默认: 今天)
|
|
417
416
|
--days <number> 查询最近n天的记录 (默认: 7)
|
|
418
417
|
|
|
418
|
+
过滤参数:
|
|
419
|
+
--author <name> 按作者过滤提交 (可选,不指定则获取所有作者)
|
|
420
|
+
--local 仅处理本地仓库
|
|
421
|
+
|
|
419
422
|
显示设置:
|
|
420
423
|
--no-color 禁用彩色输出
|
|
421
424
|
--save 保存结果到文件
|
|
425
|
+
--output <file> 保存到指定文件
|
|
422
426
|
--debug 显示调试信息
|
|
423
427
|
--show-prompt 显示完整的prompt内容
|
|
424
428
|
--version 显示当前版本号
|
|
425
429
|
|
|
426
430
|
配置管理:
|
|
427
431
|
--config 启动交互式配置向导
|
|
428
|
-
--set-api-key
|
|
432
|
+
--set-api-key 设置API密钥
|
|
429
433
|
--set-api-provider 设置API提供商 (OpenAI/DeepSeek)
|
|
430
|
-
--set-api-
|
|
434
|
+
--set-api-url 设置API基础URL
|
|
431
435
|
--set-ai-model 设置AI模型
|
|
432
|
-
--set-default-author 设置默认作者
|
|
433
|
-
--add-repo
|
|
434
|
-
--remove-repo
|
|
435
|
-
--list-repos
|
|
436
|
-
--uninstall
|
|
436
|
+
--set-default-author 设置默认作者 (可选)
|
|
437
|
+
--add-repo <alias> --path <path> 添加仓库配置
|
|
438
|
+
--remove-repo <alias> 移除仓库配置
|
|
439
|
+
--list-repos 列出所有配置的仓库
|
|
440
|
+
--uninstall 删除g2log配置文件 (~/.git-user-log-config.json)
|
|
437
441
|
|
|
438
442
|
示例:
|
|
443
|
+
g2log # 获取所有作者的提交
|
|
444
|
+
g2log --author "张三" # 只获取张三的提交
|
|
439
445
|
g2log --since "2024-01-01" --until "2024-01-31"
|
|
440
|
-
g2log --days 30
|
|
446
|
+
g2log --days 30 --local
|
|
441
447
|
g2log --config
|
|
442
448
|
g2log --set-api-key "your-api-key"
|
|
443
|
-
g2log --add-repo "alias" "path/to/repo"
|
|
444
|
-
g2log --remove-repo "alias"
|
|
449
|
+
g2log --add-repo "alias" --path "/path/to/repo"
|
|
445
450
|
g2log --list-repos
|
|
446
451
|
g2log --version
|
|
447
452
|
`);
|
|
@@ -678,7 +683,7 @@ async function summarizeWithAI(gitLogs, author, since, until, spinner = null) {
|
|
|
678
683
|
const apiProvider = config.api_provider || 'openai';
|
|
679
684
|
const apiBaseURL = config.api_base_url || '';
|
|
680
685
|
|
|
681
|
-
let prompt = config.prompt_template || `请根据以下Git
|
|
686
|
+
let prompt = config.prompt_template || `请根据以下Git提交记录,总结工作内容。
|
|
682
687
|
按照类别进行归纳,突出重点任务和成就。
|
|
683
688
|
用清晰的标题和小标题组织内容,确保总结全面且易于阅读。
|
|
684
689
|
|
|
@@ -686,10 +691,11 @@ Git提交记录:
|
|
|
686
691
|
{{GIT_LOGS}}`;
|
|
687
692
|
|
|
688
693
|
// 替换变量 - 支持多种变量格式以兼容用户自定义模板
|
|
694
|
+
const authorText = author || '所有作者';
|
|
689
695
|
prompt = prompt.replace('{{GIT_LOGS}}', gitLogs)
|
|
690
696
|
.replace('{log_content}', gitLogs) // 添加对{log_content}格式的支持
|
|
691
|
-
.replace('{{AUTHOR}}',
|
|
692
|
-
.replace('{author}',
|
|
697
|
+
.replace('{{AUTHOR}}', authorText)
|
|
698
|
+
.replace('{author}', authorText)
|
|
693
699
|
.replace('{{SINCE}}', since)
|
|
694
700
|
.replace('{since}', since)
|
|
695
701
|
.replace('{{UNTIL}}', until)
|
|
@@ -710,7 +716,8 @@ Git提交记录:
|
|
|
710
716
|
const providerLower = apiProvider.toLowerCase();
|
|
711
717
|
|
|
712
718
|
// 输出AI总结的标题信息
|
|
713
|
-
|
|
719
|
+
const summaryTitle = author ? `${author} 的工作总结` : '团队工作总结';
|
|
720
|
+
console.log(`\n${colorize('📊 ' + summaryTitle, 'bright')}`);
|
|
714
721
|
console.log(`${colorize('📅 时间范围: ' + since + ' 至 ' + until, 'green')}`);
|
|
715
722
|
console.log(`${colorize('🤖 使用模型: ' + modelName, 'cyan')}`);
|
|
716
723
|
console.log(`${colorize('=' .repeat(30), 'bright')}\n`);
|
|
@@ -1108,8 +1115,13 @@ async function getLogsFromMultipleRepos(author, since, until, options) {
|
|
|
1108
1115
|
spinner.update(`🔍 正在检查仓库 ${alias} (${repoPath})...`);
|
|
1109
1116
|
execSync(`git -C "${repoPath}" rev-parse --is-inside-work-tree`, { stdio: 'ignore' });
|
|
1110
1117
|
|
|
1111
|
-
// 构建Git
|
|
1112
|
-
let command = `git -C "${repoPath}" log --
|
|
1118
|
+
// 构建Git命令(author 现在是可选的)
|
|
1119
|
+
let command = `git -C "${repoPath}" log --since="${since}" --until="${until}" --date=format:"%Y-%m-%d %H:%M:%S"`;
|
|
1120
|
+
|
|
1121
|
+
// 如果指定了 author,则添加过滤器
|
|
1122
|
+
if (author && author.trim()) {
|
|
1123
|
+
command = `git -C "${repoPath}" log --author="${author}" --since="${since}" --until="${until}" --date=format:"%Y-%m-%d %H:%M:%S"`;
|
|
1124
|
+
}
|
|
1113
1125
|
|
|
1114
1126
|
// 添加选项
|
|
1115
1127
|
if (options.noMerges) {
|
|
@@ -1145,7 +1157,8 @@ async function getLogsFromMultipleRepos(author, since, until, options) {
|
|
|
1145
1157
|
if (logCount > 0) {
|
|
1146
1158
|
spinner.stop(`✅ 从仓库 ${repos > 1 ? `${repos} 个仓库` : Object.keys(config.repositories)[0]} 获取到 ${logCount} 条提交`);
|
|
1147
1159
|
} else {
|
|
1148
|
-
|
|
1160
|
+
const authorText = author ? author : '所有作者';
|
|
1161
|
+
spinner.stop(`📭 未找到 ${authorText} 在 ${since} 至 ${until} 期间的提交记录`);
|
|
1149
1162
|
}
|
|
1150
1163
|
|
|
1151
1164
|
return allLogs;
|
|
@@ -1222,7 +1235,7 @@ function checkConfig(silent = false) {
|
|
|
1222
1235
|
if (!silent) console.log(colorize('⚠️ 检测到配置缺失: 配置文件不存在', 'red'));
|
|
1223
1236
|
return {
|
|
1224
1237
|
needsConfig: true,
|
|
1225
|
-
missingConfig: ['api_key'
|
|
1238
|
+
missingConfig: ['api_key'],
|
|
1226
1239
|
reason: '配置文件不存在',
|
|
1227
1240
|
currentConfig: null
|
|
1228
1241
|
};
|
|
@@ -1232,14 +1245,12 @@ function checkConfig(silent = false) {
|
|
|
1232
1245
|
const config = loadConfig();
|
|
1233
1246
|
const missingConfig = [];
|
|
1234
1247
|
|
|
1235
|
-
//
|
|
1248
|
+
// 检查关键配置是否存在(default_author 现在是可选的)
|
|
1236
1249
|
if (!config.api_key) {
|
|
1237
1250
|
missingConfig.push('api_key');
|
|
1238
1251
|
}
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
missingConfig.push('default_author');
|
|
1242
|
-
}
|
|
1252
|
+
|
|
1253
|
+
// default_author 现在是可选的,不再强制要求
|
|
1243
1254
|
|
|
1244
1255
|
// 设置默认时间范围(如果不存在)
|
|
1245
1256
|
if (!config.default_since) {
|
|
@@ -1281,7 +1292,7 @@ function checkConfig(silent = false) {
|
|
|
1281
1292
|
}
|
|
1282
1293
|
return {
|
|
1283
1294
|
needsConfig: true,
|
|
1284
|
-
missingConfig: ['api_key'
|
|
1295
|
+
missingConfig: ['api_key'],
|
|
1285
1296
|
reason: `配置文件解析错误: ${error.message}`,
|
|
1286
1297
|
currentConfig: null
|
|
1287
1298
|
};
|
|
@@ -1313,45 +1324,45 @@ async function setupConfigInteractive() {
|
|
|
1313
1324
|
console.log(colorize('ℹ️ 检测到现有配置,将在其基础上进行修改。', 'blue'));
|
|
1314
1325
|
} else {
|
|
1315
1326
|
console.log(colorize('ℹ️ 未检测到配置文件,将创建新配置。', 'blue'));
|
|
1316
|
-
config = {
|
|
1327
|
+
config = {
|
|
1317
1328
|
repositories: {},
|
|
1318
|
-
prompt_template: `请根据下面的Git提交记录,用3-5
|
|
1329
|
+
prompt_template: `请根据下面的Git提交记录,用3-5句话简洁地总结工作内容。
|
|
1319
1330
|
|
|
1320
1331
|
以下是Git提交记录:
|
|
1321
1332
|
|
|
1322
1333
|
{log_content}
|
|
1323
1334
|
|
|
1324
1335
|
要求:
|
|
1325
|
-
1.
|
|
1326
|
-
2.
|
|
1336
|
+
1. 按项目、日期和作者组织内容
|
|
1337
|
+
2. 每个项目每天每个作者的工作内容用3-5句话概括
|
|
1327
1338
|
3. 使用清晰、专业但不晦涩的语言
|
|
1328
1339
|
4. 突出重要的功能开发、问题修复和优化改进
|
|
1329
1340
|
5. 适合放入工作日报的简洁描述
|
|
1330
1341
|
6. 输出格式为:【日期】:
|
|
1331
|
-
|
|
1332
|
-
|
|
1342
|
+
【项目名称】 - 【作者】 - 【工作内容概述】
|
|
1343
|
+
【项目名称】 - 【作者】 - 【工作内容概述】
|
|
1333
1344
|
7. 回复不要出现多余的内容,非必要不要用markdown格式`
|
|
1334
1345
|
};
|
|
1335
1346
|
}
|
|
1336
1347
|
} catch (error) {
|
|
1337
1348
|
console.log(colorize('⚠️ 读取配置文件时出错,将创建新配置。', 'yellow'));
|
|
1338
|
-
config = {
|
|
1349
|
+
config = {
|
|
1339
1350
|
repositories: {},
|
|
1340
|
-
prompt_template: `请根据下面的Git提交记录,用3-5
|
|
1351
|
+
prompt_template: `请根据下面的Git提交记录,用3-5句话简洁地总结工作内容。
|
|
1341
1352
|
|
|
1342
1353
|
以下是Git提交记录:
|
|
1343
1354
|
|
|
1344
1355
|
{log_content}
|
|
1345
1356
|
|
|
1346
1357
|
要求:
|
|
1347
|
-
1.
|
|
1348
|
-
2.
|
|
1358
|
+
1. 按项目、日期和作者组织内容
|
|
1359
|
+
2. 每个项目每天每个作者的工作内容用3-5句话概括
|
|
1349
1360
|
3. 使用清晰、专业但不晦涩的语言
|
|
1350
1361
|
4. 突出重要的功能开发、问题修复和优化改进
|
|
1351
1362
|
5. 适合放入工作日报的简洁描述
|
|
1352
1363
|
6. 输出格式为:【日期】:
|
|
1353
|
-
|
|
1354
|
-
|
|
1364
|
+
【项目名称】 - 【作者】 - 【工作内容概述】
|
|
1365
|
+
【项目名称】 - 【作者】 - 【工作内容概述】
|
|
1355
1366
|
7. 回复不要出现多余的内容,非必要不要用markdown格式`
|
|
1356
1367
|
};
|
|
1357
1368
|
}
|
|
@@ -1427,13 +1438,19 @@ async function setupConfigInteractive() {
|
|
|
1427
1438
|
console.log(colorize(' ℹ️ API密钥保持不变', 'blue'));
|
|
1428
1439
|
}
|
|
1429
1440
|
|
|
1430
|
-
// 步骤5:
|
|
1431
|
-
console.log(colorize('\n👤 步骤5:
|
|
1441
|
+
// 步骤5: 设置默认作者(可选)
|
|
1442
|
+
console.log(colorize('\n👤 步骤5: 设置默认作者(可选)', 'yellow'));
|
|
1432
1443
|
console.log(colorize(' (示例: 张三, user@example.com, 或Git提交时使用的用户名)', 'cyan'));
|
|
1444
|
+
console.log(colorize(' (留空则不过滤,获取所有作者的提交记录)', 'cyan'));
|
|
1433
1445
|
const existingAuthor = config.default_author || '';
|
|
1434
|
-
const authorInput = await question(colorize(` 请输入默认作者名称 [${existingAuthor}]: `, 'green'));
|
|
1435
|
-
|
|
1436
|
-
|
|
1446
|
+
const authorInput = await question(colorize(` 请输入默认作者名称 [${existingAuthor || '留空'}] (可选,按Enter跳过): `, 'green'));
|
|
1447
|
+
if (authorInput.trim() !== '') {
|
|
1448
|
+
config.default_author = authorInput.trim();
|
|
1449
|
+
console.log(colorize(` ✅ 默认作者已设置为: ${config.default_author}`, 'green'));
|
|
1450
|
+
} else {
|
|
1451
|
+
config.default_author = '';
|
|
1452
|
+
console.log(colorize(` ℹ️ 未设置默认作者,将获取所有作者的提交`, 'blue'));
|
|
1453
|
+
}
|
|
1437
1454
|
|
|
1438
1455
|
// 步骤6: 设置默认时间范围(可选)
|
|
1439
1456
|
console.log(colorize('\n🕒 步骤6: 设置默认时间范围(可选)', 'yellow'));
|
|
@@ -1582,42 +1599,21 @@ async function getGitLogs() {
|
|
|
1582
1599
|
if (isRunningWithNpx || !fs.existsSync(CONFIG_PATH)) {
|
|
1583
1600
|
// 对于NPX运行或首次使用(无配置文件),显示提示并询问是否配置
|
|
1584
1601
|
console.log(colorize('\n⚠️ 检测到配置缺失: ' + configStatus.reason, 'yellow'));
|
|
1585
|
-
|
|
1586
|
-
console.log(colorize('❗ 必须设置默认作者才能使用此工具。', 'red'));
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1602
|
+
|
|
1589
1603
|
// 创建readline接口进行简单询问
|
|
1590
1604
|
const rl = readline.createInterface({
|
|
1591
1605
|
input: process.stdin,
|
|
1592
1606
|
output: process.stdout
|
|
1593
1607
|
});
|
|
1594
|
-
|
|
1608
|
+
|
|
1595
1609
|
const question = (query) => new Promise((resolve) => rl.question(query, resolve));
|
|
1596
1610
|
const answer = await question(colorize('❓ 是否现在进行配置?(y/n): ', 'cyan'));
|
|
1597
1611
|
rl.close();
|
|
1598
|
-
|
|
1612
|
+
|
|
1599
1613
|
if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
|
|
1600
1614
|
// 启动配置向导
|
|
1601
1615
|
await setupConfigInteractive();
|
|
1602
|
-
// 配置完成后,重新加载配置
|
|
1603
|
-
const config = loadConfig();
|
|
1604
|
-
|
|
1605
|
-
// 如果依然缺少必要配置项,提示并退出
|
|
1606
|
-
if (!config.default_author || config.default_author === '') {
|
|
1607
|
-
console.log(colorize('\n❌ 错误: 未设置默认作者,这是必需的。', 'red'));
|
|
1608
|
-
console.log(colorize('💡 请使用 g2log --set-default-author="用户名" 进行设置后再试。', 'yellow'));
|
|
1609
|
-
process.exit(1);
|
|
1610
|
-
}
|
|
1611
|
-
} else if (configStatus.missingConfig.includes('default_author')) {
|
|
1612
|
-
// 如果用户拒绝配置且缺少必要的default_author,提示并退出
|
|
1613
|
-
console.log(colorize('\n❌ 错误: 未设置默认作者,这是必需的。', 'red'));
|
|
1614
|
-
console.log(colorize('💡 请使用 g2log --set-default-author="用户名" 进行设置后再试。', 'yellow'));
|
|
1615
|
-
process.exit(1);
|
|
1616
1616
|
}
|
|
1617
|
-
} else if (configStatus.missingConfig.includes('default_author')) {
|
|
1618
|
-
// 对于非NPX运行但缺少必要default_author的情况,直接错误提示
|
|
1619
|
-
console.error(colorize('❌ 错误: 配置文件中未设置默认作者。请使用 --set-default-author="用户名" 设置默认作者', 'red'));
|
|
1620
|
-
process.exit(1);
|
|
1621
1617
|
}
|
|
1622
1618
|
}
|
|
1623
1619
|
}
|
|
@@ -1765,22 +1761,18 @@ async function getGitLogs() {
|
|
|
1765
1761
|
// 显示NPX运行信息
|
|
1766
1762
|
showNpxInfo();
|
|
1767
1763
|
|
|
1768
|
-
//
|
|
1764
|
+
// 使用参数值或默认配置(author 现在是可选的)
|
|
1769
1765
|
const useLocalRepo = args.local === true;
|
|
1770
|
-
const author = config.default_author;
|
|
1766
|
+
const author = args.author || config.default_author || ''; // 支持命令行参数,可为空
|
|
1771
1767
|
const since = args.since || config.default_since;
|
|
1772
1768
|
const until = args.until || config.default_until;
|
|
1773
|
-
|
|
1769
|
+
|
|
1774
1770
|
// 其他参数从配置文件获取
|
|
1775
1771
|
const simpleMode = true; // 总是使用简单模式
|
|
1776
1772
|
const aiSummary = true; // 总是使用AI总结
|
|
1777
1773
|
const outputFile = args.output;
|
|
1778
|
-
|
|
1779
|
-
//
|
|
1780
|
-
if (!author) {
|
|
1781
|
-
console.error(colorize('错误: 配置文件中未设置默认作者。请使用 --set-default-author="用户名" 设置默认作者', 'red'));
|
|
1782
|
-
process.exit(1);
|
|
1783
|
-
}
|
|
1774
|
+
|
|
1775
|
+
// author 现在是可选的,不再强制验证
|
|
1784
1776
|
|
|
1785
1777
|
// 多仓库处理 - 如果不是--local模式,尝试处理配置中的所有仓库
|
|
1786
1778
|
if (!useLocalRepo) {
|
|
@@ -1832,15 +1824,21 @@ async function getGitLogs() {
|
|
|
1832
1824
|
}
|
|
1833
1825
|
|
|
1834
1826
|
// 获取简化格式的日志
|
|
1835
|
-
const
|
|
1836
|
-
const
|
|
1827
|
+
const authorText = author ? author : '所有作者';
|
|
1828
|
+
const logSpinner = spinner.start(`🔍 正在获取 ${authorText} 在 ${since} 至 ${until} 期间的提交记录...`);
|
|
1829
|
+
|
|
1830
|
+
// 构建Git命令(author 现在是可选的)
|
|
1831
|
+
let simpleCommand = `git -C "${repoPath}" log --since="${since}" --until="${until}" --pretty=format:"%ad: %s%n%b%n" --date=format:"%Y-%m-%d %H:%M:%S" --no-merges`;
|
|
1832
|
+
if (author && author.trim()) {
|
|
1833
|
+
simpleCommand = `git -C "${repoPath}" log --author="${author}" --since="${since}" --until="${until}" --pretty=format:"%ad: %s%n%b%n" --date=format:"%Y-%m-%d %H:%M:%S" --no-merges`;
|
|
1834
|
+
}
|
|
1837
1835
|
|
|
1838
1836
|
try {
|
|
1839
1837
|
const result = execSync(simpleCommand, { encoding: 'utf-8' });
|
|
1840
1838
|
logSpinner.stop(`✅ 找到提交记录`);
|
|
1841
1839
|
|
|
1842
1840
|
if (!result.trim()) {
|
|
1843
|
-
const message = `📭 在指定时间范围内没有找到 ${
|
|
1841
|
+
const message = `📭 在指定时间范围内没有找到 ${authorText} 的提交记录。`;
|
|
1844
1842
|
console.log(colorize(message, 'yellow'));
|
|
1845
1843
|
|
|
1846
1844
|
if (outputFile) {
|
|
@@ -1861,20 +1859,22 @@ async function getGitLogs() {
|
|
|
1861
1859
|
// 如果指定了输出文件,保存AI总结结果
|
|
1862
1860
|
if (outputFile) {
|
|
1863
1861
|
const fileSpinner = spinner.start(`💾 正在保存AI总结到文件: ${outputFile}`);
|
|
1864
|
-
|
|
1862
|
+
const summaryTitle = author ? `${author} 的工作总结` : '团队工作总结';
|
|
1863
|
+
fs.writeFileSync(outputFile, `# ${summaryTitle} (${since} 至 ${until})\n\n${aiSummaryResult}`, 'utf-8');
|
|
1865
1864
|
fileSpinner.stop(`✅ AI总结已保存到文件: ${outputFile}`);
|
|
1866
1865
|
return;
|
|
1867
1866
|
}
|
|
1868
1867
|
} catch (error) {
|
|
1869
1868
|
console.error(colorize(`❌ AI总结失败: ${error.message}`, 'red'));
|
|
1870
1869
|
// 如果AI总结失败,输出原始日志
|
|
1871
|
-
console.log(`\n📋 ${
|
|
1870
|
+
console.log(`\n📋 ${authorText} 的Git提交日志 (${since} 至 ${until})\n`);
|
|
1872
1871
|
console.log(result);
|
|
1873
|
-
|
|
1872
|
+
|
|
1874
1873
|
// 如果指定了输出文件,保存结果
|
|
1875
1874
|
if (outputFile) {
|
|
1876
1875
|
const fileSpinner = spinner.start(`💾 正在保存结果到文件: ${outputFile}`);
|
|
1877
|
-
const
|
|
1876
|
+
const summaryTitle = author ? `${author} 的Git提交日志` : 'Git提交日志';
|
|
1877
|
+
const outputContent = `# ${summaryTitle} (${since} 至 ${until})\n\n${result}`;
|
|
1878
1878
|
fs.writeFileSync(outputFile, outputContent, 'utf-8');
|
|
1879
1879
|
fileSpinner.stop(`✅ 结果已保存到文件: ${outputFile}`);
|
|
1880
1880
|
}
|
package/package.json
CHANGED