wukong-gitlog-cli 1.0.39 → 1.0.40

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 (125) hide show
  1. package/.eslintrc +1 -0
  2. package/.prettierrc +2 -1
  3. package/CHANGELOG.md +95 -0
  4. package/README.md +93 -173
  5. package/README.zh-CN.md +85 -137
  6. package/bin/wukong-gitlog-cli +0 -0
  7. package/doc//347/233/256/345/275/225/347/273/223/346/236/204.md +2871 -0
  8. package/package.json +32 -29
  9. package/rc/.wukonggitlogrc +53 -0
  10. package/scripts/compareHourlyCounts.mjs +42 -0
  11. package/scripts/compareLatest.mjs +106 -0
  12. package/src/app/analyzeAction.mjs +120 -0
  13. package/src/app/exportAction.mjs +215 -0
  14. package/src/app/exportActionProgress.mjs +37 -0
  15. package/src/app/helpers.mjs +292 -0
  16. package/src/app/initAction.mjs +110 -0
  17. package/src/app/initActionWithTemp.mjs +192 -0
  18. package/src/app/journalAction.mjs +117 -0
  19. package/src/app/overtimeAction.mjs +100 -0
  20. package/src/app/runProfileEnd.mjs +0 -0
  21. package/src/app/serveAction.mjs +73 -0
  22. package/src/app/versionAction.mjs +7 -0
  23. package/src/cli/defineOptions.mjs +209 -0
  24. package/src/cli/index.mjs +0 -0
  25. package/src/cli/parseOptions.mjs +126 -8
  26. package/src/constants/index.mjs +16 -2
  27. package/src/domain/author/analyze.mjs +6 -0
  28. package/src/domain/author/map.mjs +0 -0
  29. package/src/domain/export/exportAuthor.mjs +28 -0
  30. package/src/domain/export/exportAuthorChanges.mjs +27 -0
  31. package/src/domain/export/exportAuthorChangesJson.mjs +31 -0
  32. package/src/domain/export/exportByMonth.mjs +157 -0
  33. package/src/domain/export/exportByWeek.mjs +121 -0
  34. package/src/domain/export/exportCommits.mjs +26 -0
  35. package/src/domain/export/exportCommitsExcel.mjs +45 -0
  36. package/src/domain/export/exportCommitsJson.mjs +31 -0
  37. package/src/domain/export/index.mjs +91 -0
  38. package/src/domain/git/ensureGitAvailable.mjs +66 -0
  39. package/src/domain/git/ensureGitRepo.mjs +41 -0
  40. package/src/domain/git/getGitFeatures.mjs +59 -0
  41. package/src/domain/git/getGitLogs.mjs +326 -0
  42. package/src/domain/git/getGitUser.mjs +44 -0
  43. package/src/domain/git/getRepoRoot.mjs +32 -0
  44. package/src/domain/git/gitCapability.mjs +119 -0
  45. package/src/domain/git/index.mjs +96 -0
  46. package/src/domain/git/resolveGerrit.mjs +102 -0
  47. package/src/domain/overtime/analyze.mjs +48 -0
  48. package/src/domain/overtime/index.mjs +3 -0
  49. package/src/domain/overtime/perPeriod.mjs +15 -0
  50. package/src/domain/overtime/render.mjs +15 -0
  51. package/src/i18n/index.mjs +38 -0
  52. package/src/i18n/resources.mjs +252 -0
  53. package/src/index.mjs +132 -649
  54. package/src/infra/cache.mjs +0 -0
  55. package/src/infra/configStore.mjs +128 -0
  56. package/src/infra/fs.mjs +0 -0
  57. package/src/infra/path.mjs +0 -0
  58. package/src/output/csv/overtime.mjs +12 -0
  59. package/src/output/csv.mjs +0 -0
  60. package/src/output/data/readData.mjs +54 -0
  61. package/src/output/data/writeData.mjs +145 -0
  62. package/src/output/excel/commits.mjs +9 -0
  63. package/src/output/excel/outputExcelDayReport.mjs +92 -0
  64. package/src/output/excel/perPeriod.mjs +24 -0
  65. package/src/{excel.mjs → output/excel.mjs} +3 -2
  66. package/src/output/index.mjs +79 -0
  67. package/src/output/json/overtime.mjs +9 -0
  68. package/src/output/tab/overtime.mjs +12 -0
  69. package/src/output/tab.mjs +0 -0
  70. package/src/output/text/commits.mjs +9 -0
  71. package/src/output/text/index.mjs +3 -0
  72. package/src/output/text/outputTxtDayReport.mjs +74 -0
  73. package/src/output/text/overtime.mjs +18 -0
  74. package/src/output/utils/getEsmJs.mjs +10 -0
  75. package/src/output/utils/index.mjs +14 -0
  76. package/src/output/utils/outputPath.mjs +19 -0
  77. package/src/output/utils/writeFile.mjs +10 -0
  78. package/src/serve/index.mjs +0 -0
  79. package/src/{server.mjs → serve/startServer.mjs} +21 -3
  80. package/src/serve/writeData.mjs +0 -0
  81. package/src/utils/authorNormalizer.mjs +28 -2
  82. package/src/utils/buildAuthorChangeStats.mjs +44 -0
  83. package/src/utils/deepMerge.mjs +13 -0
  84. package/src/utils/getPackage.mjs +11 -0
  85. package/src/utils/getProfileDirFile.mjs +12 -0
  86. package/src/utils/{file.mjs → groupRecords.mjs} +8 -9
  87. package/src/utils/index.mjs +5 -2
  88. package/src/utils/logger.mjs +28 -17
  89. package/src/utils/profiler.mjs +0 -101
  90. package/src/utils/resolve.mjs +11 -0
  91. package/src/utils/showVersionInfo.mjs +6 -2
  92. package/src/utils/time.mjs +0 -0
  93. package/src/utils/wait.mjs +2 -0
  94. package/web/app.js +3197 -257
  95. package/web/index.html +171 -22
  96. package/web/revoke/alpha1/app.js +4324 -0
  97. package/web/revoke/alpha1/index.html +266 -0
  98. package/web/revoke/app.before.js +3139 -0
  99. package/web/revoke/index-before.html +181 -0
  100. package/web/static/style.css +116 -9
  101. package/src/git.mjs +0 -256
  102. package/src/handlers/handleServe.mjs +0 -203
  103. package/src/lib/configStore.mjs +0 -11
  104. package/src/lib/memoize.mjs +0 -14
  105. package/src/utils/analyzeOvertimeCached.mjs +0 -7
  106. package/src/utils/checkUpdate.mjs +0 -130
  107. package/src/utils/exitWithTime.mjs +0 -17
  108. package/src/utils/handleSuccess.mjs +0 -9
  109. package/src/utils/logDev.mjs +0 -19
  110. package/src/utils/output.mjs +0 -26
  111. package/src/utils/profiler/diff.mjs +0 -26
  112. package/src/utils/profiler/format.mjs +0 -11
  113. package/src/utils/profiler/index.mjs +0 -144
  114. package/src/utils/profiler/trace.mjs +0 -26
  115. package/src/utils/time/scopeTimer.mjs +0 -37
  116. package/src/utils/time/timer.mjs +0 -33
  117. package/src/utils/time/withTimer.mjs +0 -11
  118. package/src/utils/timer.mjs +0 -35
  119. /package/src/{overtime → domain/overtime}/createOvertimeStats.mjs +0 -0
  120. /package/src/{overtime → domain/overtime}/overtime.mjs +0 -0
  121. /package/src/{json.mjs → output/json.mjs} +0 -0
  122. /package/src/{renderAuthorMapText.mjs → output/renderAuthorMapText.mjs} +0 -0
  123. /package/src/{stats-text.mjs → output/stats-text.mjs} +0 -0
  124. /package/src/{stats.mjs → output/stats.mjs} +0 -0
  125. /package/src/{text.mjs → output/text.mjs} +0 -0
@@ -0,0 +1,102 @@
1
+ /* ---------------- helpers ---------------- */
2
+
3
+ function buildHeaders(auth) {
4
+ if (!auth) return {}
5
+ if (auth.includes(':')) {
6
+ return {
7
+ Authorization: `Basic ${Buffer.from(auth).toString('base64')}`
8
+ }
9
+ }
10
+ return { Authorization: `Bearer ${auth}` }
11
+ }
12
+
13
+ function buildGerritUrl(prefix, record, changeNumber) {
14
+ if (prefix.includes('{{changeNumber}}')) {
15
+ return prefix.replace(
16
+ '{{changeNumber}}',
17
+ changeNumber || record.changeId || record.hash
18
+ )
19
+ }
20
+ if (prefix.includes('{{changeId}}')) {
21
+ return prefix.replace('{{changeId}}', record.changeId || record.hash)
22
+ }
23
+ if (prefix.includes('{{hash}}')) {
24
+ return prefix.replace('{{hash}}', record.hash)
25
+ }
26
+ return prefix.endsWith('/')
27
+ ? `${prefix}${record.hash}`
28
+ : `${prefix}/${record.hash}`
29
+ }
30
+
31
+
32
+ /**
33
+ * @param {Object[]} records
34
+ * @param {Object} config
35
+ * @param {string} config.prefix
36
+ * @param {string} [config.api]
37
+ * @param {string} [config.auth]
38
+ */
39
+ export async function resolveGerrit(records, config) {
40
+ const { prefix, api, auth } = config
41
+ if (!prefix) return records
42
+
43
+ const cache = new Map()
44
+ const headers = buildHeaders(auth)
45
+
46
+ const fetchJson = async (url) => {
47
+ try {
48
+ const res = await fetch(url, { headers })
49
+ const txt = await res.text()
50
+ return JSON.parse(txt.replace(/^\)\]\}'\n/, ''))
51
+ } catch {
52
+ return null
53
+ }
54
+ }
55
+
56
+ const resolveChangeNumber = async (record) => {
57
+ if (!api) return null
58
+
59
+ const key = record.changeId || record.hash
60
+ if (!key) return null
61
+ if (cache.has(key)) return cache.get(key)
62
+
63
+ let json = null
64
+
65
+ if (record.changeId) {
66
+ json = await fetchJson(
67
+ `${api}/changes/${encodeURIComponent(record.changeId)}/detail`
68
+ )
69
+ if (!json?._number) {
70
+ json = await fetchJson(
71
+ `${api}/changes/?q=change:${encodeURIComponent(record.changeId)}`
72
+ )
73
+ }
74
+ }
75
+
76
+ if (!json && record.hash) {
77
+ json = await fetchJson(
78
+ `${api}/changes/?q=commit:${encodeURIComponent(record.hash)}`
79
+ )
80
+ }
81
+
82
+ const num = Array.isArray(json) ? json?.[0]?._number : json?._number
83
+ cache.set(key, num || null)
84
+ return num || null
85
+ }
86
+
87
+ return Promise.all(
88
+ records.map(async (r) => {
89
+ let changeNumber = null
90
+
91
+ if (prefix.includes('{{changeNumber}}')) {
92
+ changeNumber = await resolveChangeNumber(r)
93
+ }
94
+
95
+ return {
96
+ ...r,
97
+ gerrit: buildGerritUrl(prefix, r, changeNumber)
98
+ }
99
+ })
100
+ )
101
+ }
102
+
@@ -0,0 +1,48 @@
1
+ import { createOvertimeStats } from './createOvertimeStats.mjs'
2
+
3
+ // export function analyzeOvertime(records, worktime) {
4
+ // // 你现在的 createOvertimeStats 逻辑
5
+ // return {
6
+ // summary: {},
7
+ // byAuthor: {},
8
+ // byDay: {}
9
+ // }
10
+ // }
11
+
12
+ export function analyzeOvertime3(records, worktime) {
13
+ const stats = {
14
+ total: records.length,
15
+ offWork: 0,
16
+ weekend: 0,
17
+ byAuthor: {}
18
+ }
19
+
20
+ records.forEach((r) => {
21
+ const d = new Date(r.date)
22
+ const hour = d.getHours()
23
+ const day = d.getDay()
24
+
25
+ const isWeekend = day === 0 || day === 6
26
+ const isOffWork =
27
+ hour < worktime.start ||
28
+ hour >= worktime.end ||
29
+ (hour >= worktime.lunch.start && hour < worktime.lunch.end)
30
+
31
+ if (isWeekend) stats.weekend++
32
+ if (isOffWork) stats.offWork++
33
+
34
+ const name = r.author
35
+ stats.byAuthor[name] ||= { total: 0, offWork: 0 }
36
+ stats.byAuthor[name].total++
37
+ if (isOffWork) stats.byAuthor[name].offWork++
38
+ })
39
+
40
+ return stats
41
+ }
42
+
43
+ export const getWorkOvertimeStats = (records, opts) => {
44
+ // ❗只创建一次缓存实例
45
+ const getOvertimeStats = createOvertimeStats(opts)
46
+ const overtime = getOvertimeStats(records)
47
+ return overtime
48
+ }
@@ -0,0 +1,3 @@
1
+ export { getWorkOvertimeStats } from './analyze.mjs'
2
+ export { analyzeOvertimePerPeriod } from './perPeriod.mjs'
3
+ export * from './render.mjs'
@@ -0,0 +1,15 @@
1
+ import { groupRecords } from '../../utils/groupRecords.mjs'
2
+ import { analyzeOvertime3 } from './analyze.mjs'
3
+
4
+ export function analyzeOvertimePerPeriod(records, worktime, period) {
5
+ const groups = groupRecords(records, period)
6
+ const result = {}
7
+
8
+ Object.keys(groups)
9
+ .sort()
10
+ .forEach((key) => {
11
+ result[key] = analyzeOvertime3(groups[key], worktime)
12
+ })
13
+
14
+ return result
15
+ }
@@ -0,0 +1,15 @@
1
+ export function renderOvertimeText(stats) {
2
+ return `Total: ${stats.total}
3
+ Off-work: ${stats.offWork}
4
+ Weekend: ${stats.weekend}`
5
+ }
6
+
7
+ export function renderOvertimeCsv(stats) {
8
+ return `total,offWork,weekend
9
+ ${stats.total},${stats.offWork},${stats.weekend}`
10
+ }
11
+
12
+ export function renderOvertimeTab(stats) {
13
+ return `total\toffWork\tweekend
14
+ ${stats.total}\t${stats.offWork}\t${stats.weekend}`
15
+ }
@@ -0,0 +1,38 @@
1
+ import osLocale from 'os-locale'; // 使用同步版本更适合 CLI 启动
2
+ import { resources } from './resources.mjs'
3
+
4
+ let currentRes = resources.en
5
+
6
+ const get = (obj, path) => path.split('.').reduce((o, k) => o?.[k], obj)
7
+
8
+ /**
9
+ * 初始化国际化
10
+ * @param {string} forceLang - 用户通过 --lang 传入的强制语言
11
+ */
12
+ export function initI18n(forceLang) {
13
+ let lang = forceLang;
14
+
15
+ // 如果用户没传 --lang,则自动检测系统语言
16
+ if (!lang) {
17
+ try {
18
+ const locale = osLocale(); // 例如 'zh-CN'
19
+ lang = locale.split('-')?.[0]; // 简化为 'zh'
20
+ } catch (e) {
21
+ lang = 'en'; // 报错则保底使用英文
22
+ }
23
+ }
24
+
25
+ // 确保语言在我们的资源库中,否则回退到 en
26
+ const targetLang = resources[lang] ? lang : 'en';
27
+ currentRes = resources[targetLang];
28
+
29
+ return targetLang;
30
+ }
31
+
32
+ export const t = (key, params = {}) => {
33
+ const text = get(currentRes, key) ?? get(resources.en, key) ?? key
34
+ return text.replace(/\{\{(.+?)\}\}/g, (_, p) => {
35
+ const k = p.trim()
36
+ return params[k] !== undefined ? String(params[k]) : `{{${k}}}`
37
+ })
38
+ }
@@ -0,0 +1,252 @@
1
+ /**
2
+ * @file: resources.mjs
3
+ * @description: 国际化资源字典
4
+ */
5
+ export const resources = {
6
+ zh: {
7
+ cli: {
8
+ desc: '悟空 Gitlog:高级 Git 提交记录分析与导出工具'
9
+ },
10
+ cmds: {
11
+ init: '在当前目录初始化配置文件模板',
12
+ analyze: '分析 Git 提交记录(核心功能)',
13
+ overtime: '分析加班文化',
14
+ export: '导出记录 (Excel / CSV / JSON)',
15
+ journal: '生成每日日报',
16
+ serve: '启动本地 Web 预览服务'
17
+ },
18
+ options: {
19
+ // 全局
20
+ lang: '指定语言 (zh/en)',
21
+ debug: '启用调试日志',
22
+ info: '显示Git 环境信息',
23
+
24
+ // Git 过滤相关
25
+ author: '指定 author (建议配合别名映射使用)',
26
+ email: '指定 email',
27
+ since: '起始日期 (YYYY-MM-DD)',
28
+ until: '结束日期 (YYYY-MM-DD)',
29
+ limit: '限制解析的提交数量',
30
+ no_merges: '不包含 merge commit',
31
+ numstat: '统计增删行数 (涉及文件变更统计)',
32
+ gerrit_prefix: 'Gerrit 地址前缀 (支持 {{hash}} 占位符)',
33
+ gerrit_api: 'Gerrit REST API 基础地址',
34
+ gerrit_auth: 'Gerrit API 授权 (user:pass 或 Token)',
35
+
36
+ // 分析与加班相关
37
+ country: '节假日国家 (CN/US)',
38
+ work_start: '上班开始小时 (默认 9)',
39
+ work_end: '下班小时 (默认 18)',
40
+ lunch_start: '午休开始小时 (默认 12)',
41
+ lunch_end: '午休结束小时 (默认 14)',
42
+ overnight_cutoff: '次日凌晨归并窗口小时 (默认 6)',
43
+ overtime_mode: '启用加班文化分析模式',
44
+ group_by: '分组维度: day | month | week | all',
45
+ stats: '输出每日统计数据',
46
+
47
+ // 输出与导出
48
+ format: '输出格式: text | excel | json',
49
+ out_file: '输出文件名(不含路径)',
50
+ out_dir: '自定义输出目录',
51
+ out_parent: '输出到父目录 output-wukong/',
52
+ per_period_formats: '周期性独立输出格式 (text,csv,xlsx)',
53
+ per_period_mode: '周期性 Excel 模式 (sheets|files)',
54
+ per_period_only: '仅输出周期性文件,不合并汇总',
55
+
56
+ // Web 服务
57
+ port: '本地 Web 服务端口',
58
+
59
+ // 性能与调试
60
+ profile: '输出性能分析 JSON',
61
+ verbose: '显示详细性能日志',
62
+ flame: '显示火焰图风格日志',
63
+ trace: '生成 Chrome Trace 文件',
64
+ hot_threshold: 'HOT 比例阈值',
65
+ fail_on_hot: '当触及 HOT 阈值时 CI 报错',
66
+ diff_base: '基线 profile.json 路径',
67
+ diff_threshold: '性能回归阈值',
68
+
69
+ // Init
70
+ force: '强制覆盖已存在的配置文件(慎用)'
71
+ },
72
+ overtime: { prefix: '加班分析', complete: '加班分析完成!' },
73
+ journal: { prefix: '日报', complete: '日报任务完成' },
74
+ export: { prefix: '导出', complete: '导出任务完成' },
75
+ analyze: {
76
+ prefix: '分析', // 进度条前缀
77
+ step_git_fetch: '正在提取 Git 提交记录...',
78
+ step_git_done: 'Git 记录提取完成',
79
+ step_author_stats: '正在分析作者代码贡献...',
80
+ step_overtime_calc: '正在计算加班概况...',
81
+ step_trends: '正在生成周/月趋势数据...',
82
+ step_latest_mark: '正在标记每日最晚提交...',
83
+ step_skip_overtime: '跳过加班数据分析',
84
+ step_output: '正在持久化分析结果...',
85
+ step_complete: '分析任务全部完成!'
86
+ },
87
+ init: {
88
+ title: '配置文件初始化',
89
+ select_format: '请选择要生成的配置文件格式:',
90
+ formats: {
91
+ mjs: 'ES Module (.mjs)',
92
+ js: 'JavaScript (灵活,支持逻辑)',
93
+ yaml: 'YAML (推荐,带详细注释)',
94
+ json: 'JSON (标准格式)',
95
+ plain: 'YAML 无后缀 (.wukonggitlogrc)'
96
+ },
97
+ error_exists: '错误: 当前目录已存在配置文件',
98
+ success_created: '成功生成配置:',
99
+ gitignore_ask: '是否自动将报告目录及配置文件添加到 .gitignore?',
100
+ gitignore_updated: '已更新 .gitignore',
101
+ gitignore_warn: '无法更新 .gitignore:',
102
+ complete: '初始化完成!',
103
+ cancel: '已取消初始化',
104
+ fail: '初始化失败:'
105
+ },
106
+ // 模板注释内容 (用于生成文件)
107
+ template: {
108
+ generated_at: '生成时间',
109
+ author_config: '作者统计配置',
110
+ author_include: '[数组] 只统计这些作者,留空表示全部',
111
+ author_exclude: '[数组] 排除这些作者',
112
+ git_config: 'Git 提取配置',
113
+ git_merges: '[布尔] 是否包含 merge commit',
114
+ git_limit: '[数字] 最大拉取提交数,防止大仓拉取过慢',
115
+ period_config: '统计周期配置',
116
+ period_group: '[枚举] 统计周期: day (天) | week (周) | month (月)',
117
+ period_since: '[字符串] 起始日期 (YYYY-MM-DD)',
118
+ period_until: '[字符串] 截止日期 (YYYY-MM-DD)',
119
+ gerrit_config: 'Gerrit 链接转换 (可选)',
120
+ worktime_config: '工作时间与加班计算配置',
121
+ worktime_country: '[字符串] 国家代码 (CN/US)',
122
+ worktime_start: '[数字] 工作日开始时间',
123
+ worktime_end: '[数字] 工作日结束时间',
124
+ worktime_lunch: '午休时间',
125
+ worktime_cutoff: '[数字] 凌晨截止点',
126
+ output_config: '输出与报告配置',
127
+ output_dir: '[字符串] 报告输出目录名',
128
+ output_formats: '[数组] 输出格式',
129
+ output_per_period: '[布尔] 是否按周期生成单独文件',
130
+ author_aliases: '作者别名映射'
131
+ }
132
+ },
133
+ en: {
134
+ cli: {
135
+ desc: 'Wukong Gitlog: Advanced Git commit log exporter & analyzer.'
136
+ },
137
+ cmds: {
138
+ init: 'Initialize config template in current directory',
139
+ analyze: 'Analyze git commits (Core)',
140
+ overtime: 'Analyze overtime culture',
141
+ export: 'Export records (Excel / CSV / JSON)',
142
+ journal: 'Generate daily journal',
143
+ serve: 'Start local web preview server'
144
+ },
145
+ options: {
146
+ lang: 'Specify language (zh/en)',
147
+ debug: 'Enable debug logs',
148
+ info: 'Show Git environment information',
149
+
150
+ author: 'Specify author name (alias mapping recommended)',
151
+ email: 'Specify email',
152
+ since: 'Start date (YYYY-MM-DD)',
153
+ until: 'End date (YYYY-MM-DD)',
154
+ limit: 'Limit number of commits',
155
+ no_merges: 'Exclude merge commits',
156
+ numstat: 'Show changed files and line stats',
157
+ gerrit_prefix: 'Gerrit URL prefix (supports {{hash}})',
158
+ gerrit_api: 'Gerrit REST API base URL',
159
+ gerrit_auth: 'Gerrit API Auth (user:pass or Token)',
160
+
161
+ country: 'Holiday country code (CN/US)',
162
+ work_start: 'Work start hour (default 9)',
163
+ work_end: 'Work end hour (default 18)',
164
+ lunch_start: 'Lunch start hour (default 12)',
165
+ lunch_end: 'Lunch end hour (default 14)',
166
+ overnight_cutoff: 'Overnight cutoff hour (default 6)',
167
+ overtime_mode: 'Enable overtime analysis mode',
168
+ group_by: 'Group by: day | month | week | all',
169
+ stats: 'Output daily statistics',
170
+
171
+ format: 'Output format: text | excel | json',
172
+ out_file: 'Output filename (no path)',
173
+ out_dir: 'Custom output directory',
174
+ out_parent: 'Output to parent dir output-wukong/',
175
+ per_period_formats: 'Per-period formats (text,csv,xlsx)',
176
+ per_period_mode: 'Per-period Excel mode (sheets|files)',
177
+ per_period_only: 'Output per-period files only',
178
+
179
+ port: 'Local web server port',
180
+
181
+ profile: 'Output performance profile JSON',
182
+ verbose: 'Show verbose performance logs',
183
+ flame: 'Show flame-like logs',
184
+ trace: 'Generate Chrome Trace file',
185
+ hot_threshold: 'HOT ratio threshold',
186
+ fail_on_hot: 'Fail CI on hot threshold',
187
+ diff_base: 'Baseline profile.json path',
188
+ diff_threshold: 'Regression threshold',
189
+
190
+ force: 'Force overwrite existing config'
191
+ },
192
+ overtime: { prefix: 'Overtime', complete: 'Overtime analysis complete!' },
193
+ journal: { prefix: 'Journal', complete: 'Journal analysis complete!' },
194
+ export: { prefix: 'Export', complete: 'Export analysis complete!' },
195
+ analyze: {
196
+ prefix: 'Analyze',
197
+ step_git_fetch: 'Extracting Git commit logs...',
198
+ step_git_done: 'Git logs extraction completed',
199
+ step_author_stats: 'Analyzing author code contributions...',
200
+ step_overtime_calc: 'Calculating overtime overview...',
201
+ step_trends: 'Generating weekly/monthly trends...',
202
+ step_latest_mark: 'Marking latest daily commits...',
203
+ step_skip_overtime: 'Skipping overtime analysis',
204
+ step_output: 'Persisting analysis results...',
205
+ step_complete: 'Analysis task completed!'
206
+ },
207
+ init: {
208
+ title: 'Config Initialization',
209
+ select_format: 'Select config file format:',
210
+ formats: {
211
+ mjs: 'ES Module (.mjs)',
212
+ js: 'JavaScript (Flexible, supports logic)',
213
+ yaml: 'YAML (Recommended, with comments)',
214
+ json: 'JSON (Standard)',
215
+ plain: 'YAML no extension (.wukonggitlogrc)'
216
+ },
217
+ error_exists: 'Error: Config file already exists in current directory',
218
+ success_created: 'Config created:',
219
+ gitignore_ask: 'Add report dir and config to .gitignore automatically?',
220
+ gitignore_updated: '.gitignore updated',
221
+ gitignore_warn: 'Failed to update .gitignore:',
222
+ complete: 'Initialization complete!',
223
+ cancel: 'Initialization cancelled',
224
+ fail: 'Initialization failed:'
225
+ },
226
+ template: {
227
+ generated_at: 'Generated at',
228
+ author_config: 'Author Statistics Config',
229
+ author_include: '[Array] Include only these authors, empty for all',
230
+ author_exclude: '[Array] Exclude these authors',
231
+ git_config: 'Git Extraction Config',
232
+ git_merges: '[Boolean] Include merge commits',
233
+ git_limit: '[Number] Max commits to fetch',
234
+ period_config: 'Period Statistics Config',
235
+ period_group: '[Enum] Group by: day | week | month',
236
+ period_since: '[String] Start date (YYYY-MM-DD)',
237
+ period_until: '[String] End date (YYYY-MM-DD)',
238
+ gerrit_config: 'Gerrit Link Conversion (Optional)',
239
+ worktime_config: 'Worktime & Overtime Config',
240
+ worktime_country: '[String] Country code (CN/US)',
241
+ worktime_start: '[Number] Work start hour',
242
+ worktime_end: '[Number] Work end hour',
243
+ worktime_lunch: 'Lunch break',
244
+ worktime_cutoff: '[Number] Overnight cutoff hour',
245
+ output_config: 'Output & Report Config',
246
+ output_dir: '[String] Report output directory',
247
+ output_formats: '[Array] Output formats',
248
+ output_per_period: '[Boolean] Generate separate files per period',
249
+ author_aliases: 'Author Alias Mapping'
250
+ }
251
+ }
252
+ }