git-repo-comitter 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,26 +1,81 @@
1
1
  # git-repo-comitter
2
2
 
3
- 基于大语言模型的 Git 提交信息生成工具。
4
- 自动读取 Git 差异,调用 OpenAI 兼容 API 生成 Conventional Commits 格式的提交信息并执行提交。
3
+ 基于大语言模型的 Git 提交信息生成工具。自动读取 Git 差异,调用 OpenAI 兼容 API 生成 Conventional Commits 格式的提交信息并执行提交。
4
+
5
+ ## 特性
6
+
7
+ - 自动检测暂存/未暂存的变更,合并为完整 diff 提交给 LLM
8
+ - 支持 OpenAI 兼容 API(OpenAI、DeepSeek、通义千问等)
9
+ - 交互式初始化向导,配置持久化到 `~/.grc/config.json`
10
+ - 环境变量 `.env` 和用户配置文件双重覆盖
11
+ - 无暂存变更时自动 `git add -A`
12
+ - 内置 Conventional Commits 中文 prompt
13
+
14
+ ## 安装
15
+
16
+ ```bash
17
+ npx git-repo-comitter
18
+ ```
19
+
20
+ 本地开发:
21
+
22
+ ```bash
23
+ pnpm build && node dist/index.cjs
24
+ ```
5
25
 
6
26
  ## 使用
7
27
 
8
- 1. 配置环境变量:`LLM_API_KEY`、`LLM_ENDPOINT`、`LLM_MODEL`,或运行交互式初始化命令:
28
+ ### 快速开始
29
+
30
+ ```bash
31
+ # 交互式配置
32
+ npx git-repo-comitter init
33
+
34
+ # 生成提交信息并提交
35
+ npx git-repo-comitter
36
+ ```
37
+
38
+ 也提供别名 `grc`:
39
+
40
+ ```bash
41
+ grc init
42
+ grc
43
+ ```
44
+
45
+ ### 配置优先级
46
+
47
+ 1. 用户配置文件 `~/.grc/config.json`
48
+ 2. 项目 `.env` 文件
49
+ 3. 环境变量
50
+
51
+ ### 环境变量
52
+
53
+ | 变量 | 说明 | 默认值 |
54
+ |------|------|--------|
55
+ | `LLM_API_KEY` | API 密钥 | - |
56
+ | `LLM_ENDPOINT` | API 端点 | `https://api.openai.com/v1` |
57
+ | `LLM_MODEL` | 模型名称 | `deepseek-v4-flash` |
58
+
59
+ ### 交互式初始化
60
+
61
+ ```bash
62
+ grc init
63
+ ```
64
+
65
+ 依次设置 API 地址、模型名称、API Key。配置保存到 `~/.grc/config.json`。
9
66
 
10
- ```bash
11
- npx git-repo-comitter init
12
- ```
67
+ ## 提交信息风格
13
68
 
14
- 交互式命令会将配置保存到 `~/.grc/config.json`。
69
+ 使用 Conventional Commits 规范,中文描述。包含 `feat`、`fix`、`refactor`、`docs` 等类型,scope 可选,正文支持分条陈述。
15
70
 
16
- 2. 运行:
71
+ ## 技术栈
17
72
 
18
- ```bash
19
- # 发布后直接使用
20
- npx git-repo-comitter
73
+ - TypeScript + Vite(构建 CLI 产物为 CommonJS)
74
+ - OpenAI SDK
75
+ - YAML(用户配置解析)
76
+ - dotenv(环境变量加载)
77
+ - Husky + lint-staged + ESLint + Prettier
21
78
 
22
- # 本地开发
23
- pnpm build && node dist/index.cjs
24
- ```
79
+ ## 许可
25
80
 
26
- 也可通过 `config.yaml` 自定义模型参数和生成风格。
81
+ Unlicense 公有领域贡献。
package/dist/index.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("fs"),l=require("path"),u=require("os"),d=require("yaml");d=s(d,1);let f=require("dotenv");f=s(f,1);let p=require("child_process"),m=require("openai");m=s(m,1);let h=require("readline/promises");var g=(0,l.resolve)((0,u.homedir)(),`.grc`,`config.json`);f.default.config();var _={llm:{model:`deepseek-v4-flash`,temperature:.7,max_input_tokens:128e3,max_output_tokens:16384},style:{language:`zh-CN`,template:`conventional`},git:{repoPath:`.`},apiKey:``,endpoint:`https://api.openai.com/v1`};function v(){try{if(!(0,c.existsSync)(g))return{};let e=(0,c.readFileSync)(g,`utf-8`),t=JSON.parse(e);return{...t,llm:t.llm?{...t.llm}:void 0,style:t.style?{...t.style}:void 0,git:t.git?{...t.git}:void 0}}catch{return{}}}function y(e){let t=(0,l.resolve)((0,u.homedir)(),`.grc`);(0,c.existsSync)(t)||(0,c.mkdirSync)(t,{recursive:!0}),(0,c.writeFileSync)(g,JSON.stringify(e,null,2),`utf-8`)}function b(e){let t=e||[`.git-repo-committer.yaml`,`.git-repo-committer.yml`,`config.yaml`].find(e=>(0,c.existsSync)((0,l.resolve)(process.cwd(),e))),n={};if(t){let e=(0,c.readFileSync)((0,l.resolve)(process.cwd(),t),`utf-8`);n=d.default.parse(e)}let r=v(),i=process.env.LLM_MODEL,a=process.env.LLM_API_KEY,o=process.env.LLM_ENDPOINT;return{..._,...n,...r,llm:{..._.llm,...n.llm||{},...r.llm||{},...i?{model:i}:{}},style:{..._.style,...n.style||{},...r.style||{}},git:{..._.git,...n.git||{},...r.git||{}},apiKey:a||r.apiKey||n.apiKey||``,endpoint:o||r.endpoint||n.endpoint||_.endpoint}}function x(e){let t=e||process.cwd();try{return(0,p.execSync)(`git diff --cached`,{cwd:t,encoding:`utf-8`})}catch{return``}}function S(e){let t=e||process.cwd();try{return(0,p.execSync)(`git diff`,{cwd:t,encoding:`utf-8`})}catch{return``}}function C(e){let t=e||process.cwd(),n=x(t),r=S(t),i=[];return n.trim()&&i.push(`=== Staged Changes ===
3
- `+n),r.trim()&&i.push(`=== Unstaged Changes ===
4
- `+r),i.join(`
2
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("fs"),l=require("path"),u=require("os"),d=require("child_process"),f=require("openai");f=s(f,1);let p=require("readline/promises");var m=(0,l.resolve)((0,u.homedir)(),`.grc`,`config.json`),h={llm:{model:`deepseek-v4-flash`,temperature:.7,max_input_tokens:262144,max_output_tokens:16384},apiKey:``,endpoint:`https://api.openai.com/v1`};function g(){try{if(!(0,c.existsSync)(m))return{};let e=(0,c.readFileSync)(m,`utf-8`),t=JSON.parse(e);return{...t,llm:t.llm?{...t.llm}:void 0}}catch{return{}}}function _(e){let t=(0,l.resolve)((0,u.homedir)(),`.grc`);(0,c.existsSync)(t)||(0,c.mkdirSync)(t,{recursive:!0}),(0,c.writeFileSync)(m,JSON.stringify(e,null,2),`utf-8`)}function v(){let e=g(),t=process.env.LLM_MODEL,n=process.env.LLM_API_KEY,r=process.env.LLM_ENDPOINT;return{...h,...e,llm:{...h.llm,...e.llm||{},...t?{model:t}:{}},apiKey:n||e.apiKey||``,endpoint:r||e.endpoint||h.endpoint}}function y(){try{return(0,d.execSync)(`git diff --cached`,{cwd:process.cwd(),encoding:`utf-8`})}catch{return``}}function b(){try{return(0,d.execSync)(`git diff`,{cwd:process.cwd(),encoding:`utf-8`})}catch{return``}}function x(){let e=y(),t=b(),n=[];return e.trim()&&n.push(`=== Staged Changes ===
3
+ `+e),t.trim()&&n.push(`=== Unstaged Changes ===
4
+ `+t),n.join(`
5
5
 
6
- `)}function w(e){let t=e||process.cwd();try{return(0,p.execSync)(`git diff --cached --name-only`,{cwd:t,encoding:`utf-8`}).trim().length>0}catch{return!1}}var T=`你是一位擅长编写 Git 提交信息的专家。根据提供的 Git diff,生成简洁且描述准确的提交信息。
6
+ `)}function S(){try{return(0,d.execSync)(`git diff --cached --name-only`,{cwd:process.cwd(),encoding:`utf-8`}).trim().length>0}catch{return!1}}function C(e){let t=(typeof e==`string`?JSON.parse(e):e).choices?.[0]?.message?.content;return typeof t==`string`?t.trim():Array.isArray(t)?t.filter(e=>e.type===`text`).map(e=>e.text).join(``).trim():``}function w(e){let t=(0,p.createInterface)({input:process.stdin,output:process.stdout});return t.question(e).finally(()=>t.close())}var T=`你是一位擅长编写 Git 提交信息的专家。根据提供的 Git diff,生成简洁且描述准确的提交信息。
7
7
 
8
8
  格式规范:
9
9
  - 遵循 Conventional Commits:<type>(<scope>): <description>
@@ -33,9 +33,9 @@ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=
33
33
  - 迁移 session 和 permission 模块至新接口
34
34
  - 移除已废弃的 getCacheKey 方法
35
35
 
36
- 只回复提交信息本身,不要添加任何解释。`;function E(e){let t=(typeof e==`string`?JSON.parse(e):e).choices?.[0]?.message?.content;return typeof t==`string`?t.trim():Array.isArray(t)?t.filter(e=>e.type===`text`).map(e=>e.text).join(``).trim():``}async function D(e,t){if(!t.apiKey)throw Error(`LLM_API_KEY is not set. Please set it in .env or environment variables.`);let n=await new m.default({apiKey:t.apiKey,baseURL:t.endpoint}).chat.completions.create({model:t.llm.model,temperature:t.llm.temperature,max_tokens:t.llm.max_output_tokens,messages:[{role:`system`,content:T},{role:`user`,content:`以下是 Git diff 内容:\n\n${e}`}]}),r=E(n);if(!r)throw Error(`LLM returned an empty commit message. Response: ${JSON.stringify(n)}`);return r}function O(e,t){let n=t||process.cwd();(0,p.execSync)(`git commit -m "${e.replace(/"/g,`\\"`)}"`,{cwd:n,encoding:`utf-8`})}function k(e){(0,p.execSync)(`git add -A`,{cwd:e||process.cwd(),encoding:`utf-8`})}function A(e){let t=(0,h.createInterface)({input:process.stdin,output:process.stdout});return t.question(e).finally(()=>t.close())}async function j(){console.log(`LLM 配置初始化
37
- `);let e=v(),t=(await A(`大模型链接 (API 地址) [${e.endpoint||`https://api.openai.com/v1`}]: `)).trim()||e.endpoint||`https://api.openai.com/v1`,n=(await A(`模型名称 [${e.llm?.model||`deepseek-v4-flash`}]: `)).trim()||e.llm?.model||`deepseek-v4-flash`,r=(await A(`API Key [${e.apiKey?`***`:`(必填)`}]: `)).trim()||e.apiKey;r||(console.error(`
38
- 错误:API Key 不能为空。`),process.exit(1)),y({apiKey:r,endpoint:t,llm:{model:n,temperature:.7,max_input_tokens:262144,max_output_tokens:16384}}),console.log(`
39
- 配置已保存到 ~/.grc/config.json`)}async function M(){let e=b();e.apiKey||(console.error(`Error: LLM_API_KEY is not set. Please set it in .env or environment variables.`),process.exit(1)),w(e.git.repoPath)||(console.log(`No staged changes found. Staging all changes...`),k(e.git.repoPath));let t=C(e.git.repoPath);t.trim()||(console.log(`No changes to commit.`),process.exit(0)),console.log(`Generating commit message...
40
- `);let n=await D(t,e);console.log(`Commit message:\n ${n}\n`),O(n,e.git.repoPath),console.log(`Commit successful!`)}async function N(){process.argv[2]===`init`?await j():await M()}N().catch(e=>{console.error(`Error:`,e.message),process.exit(1)});
36
+ 只回复提交信息本身,不要添加任何解释。`;async function E(e,t){if(!t.apiKey)throw Error(`LLM_API_KEY is not set. Please set it in .env or environment variables.`);let n=await new f.default({apiKey:t.apiKey,baseURL:t.endpoint}).chat.completions.create({model:t.llm.model,temperature:t.llm.temperature,max_tokens:t.llm.max_output_tokens,messages:[{role:`system`,content:T},{role:`user`,content:`以下是 Git diff 内容:\n\n${e}`}]}),r=C(n);if(!r)throw Error(`LLM returned an empty commit message. Response: ${JSON.stringify(n)}`);return r}function D(e){(0,d.execSync)(`git commit -m "${e.replace(/"/g,`\\"`)}"`,{cwd:process.cwd(),encoding:`utf-8`})}function O(){(0,d.execSync)(`git add -A`,{cwd:process.cwd(),encoding:`utf-8`})}async function k(){console.log(`LLM 配置初始化
37
+ `);let e=g(),t=(await w(`大模型链接 (API 地址) [${e.endpoint||`https://api.openai.com/v1`}]: `)).trim()||e.endpoint||`https://api.openai.com/v1`,n=(await w(`模型名称 [${e.llm?.model||`deepseek-v4-flash`}]: `)).trim()||e.llm?.model||`deepseek-v4-flash`,r=(await w(`API Key [${e.apiKey?`***`:`(必填)`}]: `)).trim()||e.apiKey;r||(console.error(`
38
+ 错误:API Key 不能为空。`),process.exit(1)),_({apiKey:r,endpoint:t,llm:{model:n,temperature:.7,max_input_tokens:262144,max_output_tokens:16384}}),console.log(`
39
+ 配置已保存到 ~/.grc/config.json`)}async function A(){let e=v();e.apiKey||(console.error("Error: LLM_API_KEY is not set. Please run `grc init` to configure."),process.exit(1)),S()||(console.log(`No staged changes found. Staging all changes...`),O());let t=x();t.trim()||(console.log(`No changes to commit.`),process.exit(0)),console.log(`Generating commit message...
40
+ `);let n=await E(t,e);console.log(`Commit message:\n ${n}\n`),D(n),console.log(`Commit successful!`)}async function j(){process.argv[2]===`init`?await k():await A()}j().catch(e=>{console.error(`Error:`,e.message),process.exit(1)});
41
41
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/config.ts","../src/git.ts","../src/llm.ts","../src/commit.ts","../src/init.ts","../src/index.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync, mkdirSync } from \"fs\";\nimport { resolve } from \"path\";\nimport { homedir } from \"os\";\nimport YAML from \"yaml\";\nimport dotenv from \"dotenv\";\n\n\nconst USER_CONFIG_PATH = resolve(homedir(), \".grc\", \"config.json\");\ndotenv.config();\n\nexport interface LLMConfig {\n model: string;\n temperature: number;\n max_input_tokens: number;\n max_output_tokens: number;\n}\n\nexport interface StyleConfig {\n language: string;\n template: string;\n}\n\nexport interface GitConfig {\n repoPath: string;\n}\n\nexport interface AppConfig {\n llm: LLMConfig;\n style: StyleConfig;\n git: GitConfig;\n apiKey: string;\n endpoint: string;\n}\nconst DEFAULT_CONFIG: AppConfig = {\n llm: {\n model: \"deepseek-v4-flash\",\n temperature: 0.7,\n max_input_tokens: 128000,\n max_output_tokens: 16384,\n },\n style: {\n language: \"zh-CN\",\n template: \"conventional\",\n },\n git: {\n repoPath: \".\",\n },\n apiKey: \"\",\n endpoint: \"https://api.openai.com/v1\",\n};\nexport function loadUserConfig(): Partial<AppConfig> {\n try {\n if (!existsSync(USER_CONFIG_PATH)) return {};\n const raw = readFileSync(USER_CONFIG_PATH, \"utf-8\");\n const parsed = JSON.parse(raw);\n return {\n ...parsed,\n llm: parsed.llm ? { ...parsed.llm } : undefined,\n style: parsed.style ? { ...parsed.style } : undefined,\n git: parsed.git ? { ...parsed.git } : undefined,\n };\n } catch {\n return {};\n }\n}\n\nexport function saveUserConfig(config: Partial<AppConfig>): void {\n const dir = resolve(homedir(), \".grc\");\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n writeFileSync(USER_CONFIG_PATH, JSON.stringify(config, null, 2), \"utf-8\");\n}\n\nexport function loadConfig(configPath?: string): AppConfig {\n const configFile =\n configPath ||\n [\".git-repo-committer.yaml\", \".git-repo-committer.yml\", \"config.yaml\"].find(\n (f) => existsSync(resolve(process.cwd(), f)),\n );\n\n let fileConfig: Partial<AppConfig> = {};\n\n if (configFile) {\n const content = readFileSync(resolve(process.cwd(), configFile), \"utf-8\");\n fileConfig = YAML.parse(content);\n }\n\n const userConfig = loadUserConfig();\n\n const envModel = process.env.LLM_MODEL;\n const envApiKey = process.env.LLM_API_KEY;\n const envEndpoint = process.env.LLM_ENDPOINT;\n\n return {\n ...DEFAULT_CONFIG,\n ...fileConfig,\n ...userConfig,\n llm: {\n ...DEFAULT_CONFIG.llm,\n ...(fileConfig.llm || {}),\n ...(userConfig.llm || {}),\n ...(envModel ? { model: envModel } : {}),\n },\n style: { ...DEFAULT_CONFIG.style, ...(fileConfig.style || {}), ...(userConfig.style || {}) },\n git: { ...DEFAULT_CONFIG.git, ...(fileConfig.git || {}), ...(userConfig.git || {}) },\n apiKey: envApiKey || userConfig.apiKey || fileConfig.apiKey || \"\",\n endpoint: envEndpoint || userConfig.endpoint || fileConfig.endpoint || DEFAULT_CONFIG.endpoint,\n };\n}\n","import { execSync } from \"child_process\";\n\nexport function getStagedDiff(repoPath?: string): string {\n const cwd = repoPath || process.cwd();\n try {\n return execSync(\"git diff --cached\", { cwd, encoding: \"utf-8\" });\n } catch {\n return \"\";\n }\n}\n\nexport function getUnstagedDiff(repoPath?: string): string {\n const cwd = repoPath || process.cwd();\n try {\n return execSync(\"git diff\", { cwd, encoding: \"utf-8\" });\n } catch {\n return \"\";\n }\n}\n\nexport function getAllDiff(repoPath?: string): string {\n const cwd = repoPath || process.cwd();\n const staged = getStagedDiff(cwd);\n const unstaged = getUnstagedDiff(cwd);\n\n const parts: string[] = [];\n if (staged.trim()) {\n parts.push(\"=== Staged Changes ===\\n\" + staged);\n }\n if (unstaged.trim()) {\n parts.push(\"=== Unstaged Changes ===\\n\" + unstaged);\n }\n return parts.join(\"\\n\\n\");\n}\n\nexport function hasStagedChanges(repoPath?: string): boolean {\n const cwd = repoPath || process.cwd();\n try {\n const result = execSync(\"git diff --cached --name-only\", {\n cwd,\n encoding: \"utf-8\",\n });\n return result.trim().length > 0;\n } catch {\n return false;\n }\n}\n","import OpenAI from \"openai\";\nimport type { AppConfig } from \"./config\";\n\nconst SYSTEM_PROMPT = `你是一位擅长编写 Git 提交信息的专家。根据提供的 Git diff,生成简洁且描述准确的提交信息。\n\n格式规范:\n- 遵循 Conventional Commits:<type>(<scope>): <description>\n- type 可选值:feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert\n- 标题行控制在 72 字符以内\n- 正文使用无序列表分条陈述,每条以 \"- \" 开头\n- 如变更较简单,可省略正文,仅保留标题行\n- 标题和正文之间用空行隔开\n- 提交的信息必须符合 Conventional Commits 格式\n- 描述语言使用中文,避免使用英文。\n\n示例:\n1. 仅标题行:\n fix(auth): 修复登录重定向丢失 query 参数的问题\n\n2. 标题 + 正文:\n feat(api): 新增用户批量导入接口\n\n - 支持 CSV 和 JSON 两种文件格式\n - 单次最多处理 1000 条记录\n - 导入失败时返回逐条错误详情\n\n3. 多处关联变更:\n refactor(storage): 统一缓存键的生成逻辑\n\n - 抽取 keyBuilder 工具函数替代各处硬编码\n - 迁移 session 和 permission 模块至新接口\n - 移除已废弃的 getCacheKey 方法\n\n只回复提交信息本身,不要添加任何解释。`;\n\nfunction extractContent(response: any): string {\n const data = typeof response === \"string\" ? JSON.parse(response) : response;\n const content = data.choices?.[0]?.message?.content;\n if (typeof content === \"string\") return content.trim();\n if (Array.isArray(content)) {\n return content\n .filter((c: any) => c.type === \"text\")\n .map((c: any) => c.text)\n .join(\"\")\n .trim();\n }\n return \"\";\n}\n\nexport async function generateCommitMessage(\n diff: string,\n config: AppConfig,\n): Promise<string> {\n if (!config.apiKey) {\n throw new Error(\n \"LLM_API_KEY is not set. Please set it in .env or environment variables.\",\n );\n }\n\n const client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.endpoint,\n });\n\n const response = await client.chat.completions.create({\n model: config.llm.model,\n temperature: config.llm.temperature,\n max_tokens: config.llm.max_output_tokens,\n messages: [\n { role: \"system\", content: SYSTEM_PROMPT },\n {\n role: \"user\",\n content: `以下是 Git diff 内容:\\n\\n${diff}`,\n },\n ],\n });\n\n const message = extractContent(response);\n if (!message) {\n throw new Error(\n `LLM returned an empty commit message. Response: ${JSON.stringify(response)}`,\n );\n }\n return message;\n}\n","import { execSync } from \"child_process\";\n\nexport function gitCommit(message: string, repoPath?: string): void {\n const cwd = repoPath || process.cwd();\n const escapedMessage = message.replace(/\"/g, '\\\\\"');\n execSync(`git commit -m \"${escapedMessage}\"`, { cwd, encoding: \"utf-8\" });\n}\n\nexport function gitAddAll(repoPath?: string): void {\n const cwd = repoPath || process.cwd();\n execSync(\"git add -A\", { cwd, encoding: \"utf-8\" });\n}\n","import { createInterface } from \"readline/promises\";\nimport { loadUserConfig, saveUserConfig } from \"./config\";\n\nfunction question(query: string): Promise<string> {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return rl.question(query).finally(() => rl.close());\n}\n\nexport async function runInit(): Promise<void> {\n console.log(\"LLM 配置初始化\\n\");\n\n const existing = loadUserConfig();\n\n const endpoint =\n (await question(\n `大模型链接 (API 地址) [${existing.endpoint || \"https://api.openai.com/v1\"}]: `,\n )).trim() || existing.endpoint || \"https://api.openai.com/v1\";\n\n const model =\n (await question(\n `模型名称 [${existing.llm?.model || \"deepseek-v4-flash\"}]: `,\n )).trim() || existing.llm?.model || \"deepseek-v4-flash\";\n\n const apiKey =\n (await question(\n `API Key [${existing.apiKey ? \"***\" : \"(必填)\"}]: `,\n )).trim() || existing.apiKey;\n\n if (!apiKey) {\n console.error(\"\\n错误:API Key 不能为空。\");\n process.exit(1);\n }\n\n saveUserConfig({ apiKey, endpoint, llm: { model, temperature: 0.7, max_input_tokens: 262144, max_output_tokens: 16384 } });\n console.log(\"\\n配置已保存到 ~/.grc/config.json\");\n}\n","import { loadConfig } from \"./config\";\nimport { getAllDiff, hasStagedChanges } from \"./git\";\nimport { generateCommitMessage } from \"./llm\";\nimport { gitCommit, gitAddAll } from \"./commit\";\nimport { runInit } from \"./init\";\n\nasync function runCommit() {\n const config = loadConfig();\n\n if (!config.apiKey) {\n console.error(\n \"Error: LLM_API_KEY is not set. Please set it in .env or environment variables.\",\n );\n process.exit(1);\n }\n\n if (!hasStagedChanges(config.git.repoPath)) {\n console.log(\"No staged changes found. Staging all changes...\");\n gitAddAll(config.git.repoPath);\n }\n\n const diff = getAllDiff(config.git.repoPath);\n if (!diff.trim()) {\n console.log(\"No changes to commit.\");\n process.exit(0);\n }\n\n console.log(\"Generating commit message...\\n\");\n const message = await generateCommitMessage(diff, config);\n console.log(`Commit message:\\n ${message}\\n`);\n\n gitCommit(message, config.git.repoPath);\n console.log(\"Commit successful!\");\n}\n\nasync function main() {\n const subcommand = process.argv[2];\n\n if (subcommand === \"init\") {\n await runInit();\n } else {\n await runCommit();\n }\n}\n\nmain().catch((err) => {\n console.error(\"Error:\", err.message);\n process.exit(1);\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/config.ts","../src/git.ts","../src/util.ts","../src/llm.ts","../src/commit.ts","../src/init.ts","../src/index.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync, mkdirSync } from \"fs\";\nimport { resolve } from \"path\";\nimport { homedir } from \"os\";\n\nconst USER_CONFIG_PATH = resolve(homedir(), \".grc\", \"config.json\");\n\nexport interface LLMConfig {\n model: string;\n temperature: number;\n max_input_tokens: number;\n max_output_tokens: number;\n}\n\nexport interface AppConfig {\n llm: LLMConfig;\n apiKey: string;\n endpoint: string;\n}\n\nconst DEFAULT_CONFIG: AppConfig = {\n llm: {\n model: \"deepseek-v4-flash\",\n temperature: 0.7,\n max_input_tokens: 262144,\n max_output_tokens: 16384,\n },\n apiKey: \"\",\n endpoint: \"https://api.openai.com/v1\",\n};\n\nexport function loadUserConfig(): Partial<AppConfig> {\n try {\n if (!existsSync(USER_CONFIG_PATH)) return {};\n const raw = readFileSync(USER_CONFIG_PATH, \"utf-8\");\n const parsed = JSON.parse(raw);\n return {\n ...parsed,\n llm: parsed.llm ? { ...parsed.llm } : undefined,\n };\n } catch {\n return {};\n }\n}\n\nexport function saveUserConfig(config: Partial<AppConfig>): void {\n const dir = resolve(homedir(), \".grc\");\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n writeFileSync(USER_CONFIG_PATH, JSON.stringify(config, null, 2), \"utf-8\");\n}\n\nexport function loadConfig(): AppConfig {\n const userConfig = loadUserConfig();\n\n const envModel = process.env.LLM_MODEL;\n const envApiKey = process.env.LLM_API_KEY;\n const envEndpoint = process.env.LLM_ENDPOINT;\n\n return {\n ...DEFAULT_CONFIG,\n ...userConfig,\n llm: {\n ...DEFAULT_CONFIG.llm,\n ...(userConfig.llm || {}),\n ...(envModel ? { model: envModel } : {}),\n },\n apiKey: envApiKey || userConfig.apiKey || \"\",\n endpoint: envEndpoint || userConfig.endpoint || DEFAULT_CONFIG.endpoint,\n };\n}","import { execSync } from \"child_process\";\n\nfunction getStagedDiff(): string {\n try {\n return execSync(\"git diff --cached\", { cwd: process.cwd(), encoding: \"utf-8\" });\n } catch {\n return \"\";\n }\n}\n\nfunction getUnstagedDiff(): string {\n try {\n return execSync(\"git diff\", { cwd: process.cwd(), encoding: \"utf-8\" });\n } catch {\n return \"\";\n }\n}\n\nexport function getAllDiff(): string {\n const staged = getStagedDiff();\n const unstaged = getUnstagedDiff();\n\n const parts: string[] = [];\n if (staged.trim()) {\n parts.push(\"=== Staged Changes ===\\n\" + staged);\n }\n if (unstaged.trim()) {\n parts.push(\"=== Unstaged Changes ===\\n\" + unstaged);\n }\n return parts.join(\"\\n\\n\");\n}\n\nexport function hasStagedChanges(): boolean {\n try {\n const result = execSync(\"git diff --cached --name-only\", {\n cwd: process.cwd(),\n encoding: \"utf-8\",\n });\n return result.trim().length > 0;\n } catch {\n return false;\n }\n}","import { createInterface } from \"readline/promises\";\n\nexport interface MessageContentPart {\n type: string;\n text: string;\n}\n\nexport interface ChatCompletionMessage {\n content: string | MessageContentPart[] | null;\n}\n\nexport interface ChatCompletionChoice {\n message: ChatCompletionMessage;\n}\n\nexport interface ChatCompletionResponse {\n choices: ChatCompletionChoice[];\n}\n\nexport function extractContent(response: ChatCompletionResponse | string): string {\n const data = typeof response === \"string\" ? JSON.parse(response) : response;\n const content = data.choices?.[0]?.message?.content;\n if (typeof content === \"string\") return content.trim();\n if (Array.isArray(content)) {\n return content\n .filter((c) => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\")\n .trim();\n }\n return \"\";\n}\n\nexport function question(query: string): Promise<string> {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return rl.question(query).finally(() => rl.close());\n}","import OpenAI from \"openai\";\nimport type { AppConfig } from \"./config\";\nimport { extractContent } from \"./util\";\n\nconst SYSTEM_PROMPT = `你是一位擅长编写 Git 提交信息的专家。根据提供的 Git diff,生成简洁且描述准确的提交信息。\n\n格式规范:\n- 遵循 Conventional Commits:<type>(<scope>): <description>\n- type 可选值:feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert\n- 标题行控制在 72 字符以内\n- 正文使用无序列表分条陈述,每条以 \"- \" 开头\n- 如变更较简单,可省略正文,仅保留标题行\n- 标题和正文之间用空行隔开\n- 提交的信息必须符合 Conventional Commits 格式\n- 描述语言使用中文,避免使用英文。\n\n示例:\n1. 仅标题行:\n fix(auth): 修复登录重定向丢失 query 参数的问题\n\n2. 标题 + 正文:\n feat(api): 新增用户批量导入接口\n\n - 支持 CSV 和 JSON 两种文件格式\n - 单次最多处理 1000 条记录\n - 导入失败时返回逐条错误详情\n\n3. 多处关联变更:\n refactor(storage): 统一缓存键的生成逻辑\n\n - 抽取 keyBuilder 工具函数替代各处硬编码\n - 迁移 session 和 permission 模块至新接口\n - 移除已废弃的 getCacheKey 方法\n\n只回复提交信息本身,不要添加任何解释。`;\n\nexport async function generateCommitMessage(\n diff: string,\n config: AppConfig,\n): Promise<string> {\n if (!config.apiKey) {\n throw new Error(\n \"LLM_API_KEY is not set. Please set it in .env or environment variables.\",\n );\n }\n\n const client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.endpoint,\n });\n\n const response = await client.chat.completions.create({\n model: config.llm.model,\n temperature: config.llm.temperature,\n max_tokens: config.llm.max_output_tokens,\n messages: [\n { role: \"system\", content: SYSTEM_PROMPT },\n {\n role: \"user\",\n content: `以下是 Git diff 内容:\\n\\n${diff}`,\n },\n ],\n });\n\n const message = extractContent(response);\n if (!message) {\n throw new Error(\n `LLM returned an empty commit message. Response: ${JSON.stringify(response)}`,\n );\n }\n return message;\n}","import { execSync } from \"child_process\";\n\nexport function gitCommit(message: string): void {\n const escapedMessage = message.replace(/\"/g, '\\\\\"');\n execSync(`git commit -m \"${escapedMessage}\"`, {\n cwd: process.cwd(),\n encoding: \"utf-8\",\n });\n}\n\nexport function gitAddAll(): void {\n execSync(\"git add -A\", { cwd: process.cwd(), encoding: \"utf-8\" });\n}","import { loadUserConfig, saveUserConfig } from \"./config\";\nimport { question } from \"./util\";\n\nexport async function runInit(): Promise<void> {\n console.log(\"LLM 配置初始化\\n\");\n\n const existing = loadUserConfig();\n\n const endpoint =\n (\n await question(\n `大模型链接 (API 地址) [${existing.endpoint || \"https://api.openai.com/v1\"}]: `,\n )\n ).trim() ||\n existing.endpoint ||\n \"https://api.openai.com/v1\";\n\n const model =\n (\n await question(\n `模型名称 [${existing.llm?.model || \"deepseek-v4-flash\"}]: `,\n )\n ).trim() ||\n existing.llm?.model ||\n \"deepseek-v4-flash\";\n\n const apiKey =\n (\n await question(`API Key [${existing.apiKey ? \"***\" : \"(必填)\"}]: `)\n ).trim() || existing.apiKey;\n\n if (!apiKey) {\n console.error(\"\\n错误:API Key 不能为空。\");\n process.exit(1);\n }\n\n saveUserConfig({\n apiKey,\n endpoint,\n llm: { model, temperature: 0.7, max_input_tokens: 262144, max_output_tokens: 16384 },\n });\n console.log(\"\\n配置已保存到 ~/.grc/config.json\");\n}","import { loadConfig } from \"./config\";\nimport { getAllDiff, hasStagedChanges } from \"./git\";\nimport { generateCommitMessage } from \"./llm\";\nimport { gitCommit, gitAddAll } from \"./commit\";\nimport { runInit } from \"./init\";\n\nasync function runCommit() {\n const config = loadConfig();\n\n if (!config.apiKey) {\n console.error(\n \"Error: LLM_API_KEY is not set. Please run `grc init` to configure.\",\n );\n process.exit(1);\n }\n\n if (!hasStagedChanges()) {\n console.log(\"No staged changes found. Staging all changes...\");\n gitAddAll();\n }\n\n const diff = getAllDiff();\n if (!diff.trim()) {\n console.log(\"No changes to commit.\");\n process.exit(0);\n }\n\n console.log(\"Generating commit message...\\n\");\n const message = await generateCommitMessage(diff, config);\n console.log(`Commit message:\\n ${message}\\n`);\n\n gitCommit(message);\n console.log(\"Commit successful!\");\n}\n\nasync function main() {\n const subcommand = process.argv[2];\n\n if (subcommand === \"init\") {\n await runInit();\n } else {\n await runCommit();\n }\n}\n\nmain().catch((err) => {\n console.error(\"Error:\", err.message);\n process.exit(1);\n});"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-repo-comitter",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "A CLI tool that uses LLM to generate Git commit messages and execute commits",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -47,11 +47,13 @@
47
47
  ]
48
48
  },
49
49
  "devDependencies": {
50
+ "@eslint/js": "^10.0.1",
50
51
  "@types/node": "^26.1.1",
51
52
  "@typescript-eslint/eslint-plugin": "^8.63.0",
52
53
  "@typescript-eslint/parser": "^8.63.0",
53
54
  "eslint": "^10.7.0",
54
55
  "eslint-config-prettier": "^10.1.8",
56
+ "globals": "^17.7.0",
55
57
  "husky": "^9.1.7",
56
58
  "lint-staged": "^16.4.0",
57
59
  "prettier": "^3.9.5",