git-repo-comitter 0.2.5 → 0.3.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/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "git-repo-comitter",
3
- "version": "0.2.5",
3
+ "version": "0.3.0",
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",
7
7
  "bin": {
8
8
  "git-repo-comitter": "dist/index.cjs"
9
9
  },
10
+ "files": [
11
+ "dist"
12
+ ],
10
13
  "scripts": {
11
14
  "dev": "vite",
12
15
  "build": "tsc && vite build",
package/.env.example DELETED
@@ -1,3 +0,0 @@
1
- LLM_API_KEY=your-api-key-here
2
- LLM_ENDPOINT=https://api.openai.com/v1
3
- LLM_MODEL=deepseek-v4-flash
package/.eslintrc.cjs DELETED
@@ -1,19 +0,0 @@
1
- module.exports = {
2
- root: true,
3
- parser: "@typescript-eslint/parser",
4
- plugins: ["@typescript-eslint"],
5
- extends: [
6
- "eslint:recommended",
7
- "plugin:@typescript-eslint/recommended",
8
- "prettier",
9
- ],
10
- env: {
11
- node: true,
12
- es2020: true,
13
- },
14
- parserOptions: {
15
- ecmaVersion: 2020,
16
- sourceType: "module",
17
- },
18
- rules: {},
19
- };
@@ -1,34 +0,0 @@
1
- name: Publish Package
2
-
3
- on:
4
- push:
5
- tags:
6
- - "v*"
7
-
8
- permissions:
9
- id-token: write
10
- contents: read
11
-
12
- jobs:
13
- publish:
14
- runs-on: ubuntu-latest
15
- steps:
16
- - uses: actions/checkout@v6
17
-
18
- - uses: pnpm/action-setup@v6
19
- with:
20
- version: "10"
21
-
22
- - uses: actions/setup-node@v6
23
- with:
24
- node-version: "24"
25
- registry-url: "https://registry.npmjs.org"
26
- package-manager-cache: false
27
-
28
- - run: npm install -g npm@latest
29
-
30
- - run: pnpm install --frozen-lockfile
31
-
32
- - run: pnpm build
33
-
34
- - run: npm publish --provenance --access public
package/.prettierrc DELETED
@@ -1,7 +0,0 @@
1
- {
2
- "semi": true,
3
- "singleQuote": false,
4
- "tabWidth": 2,
5
- "trailingComma": "all",
6
- "printWidth": 80
7
- }
package/config.yaml DELETED
@@ -1,16 +0,0 @@
1
- # Git Repo Committer 配置文件
2
-
3
- # 大模型配置
4
- llm:
5
- model: "gpt-4"
6
- temperature: 0.7
7
- max_tokens: 256
8
-
9
- # 生成风格模板
10
- style:
11
- language: "zh-CN"
12
- template: "conventional" # conventional | conventional-commit | custom
13
-
14
- # Git 目录路径(默认为当前目录)
15
- git:
16
- repoPath: "."
@@ -1,143 +0,0 @@
1
- # 项目初始化
2
-
3
- ## 项目概述
4
-
5
- 本项目是一个基于 TypeScript 的前端工具,用于调用大语言模型(采用 OpenAI 兼容格式),管理 Git 差异(diff),自动生成 Git 提交信息(commit message),并执行提交操作。
6
-
7
- ## 技术栈
8
-
9
- - 编程语言:TypeScript
10
- - 构建工具:Vite
11
- - 包管理器:npm
12
- - 代码格式化:Prettier + ESLint
13
- - Git 钩子:husky + lint-staged
14
-
15
- ## 功能需求
16
-
17
- ### 核心功能
18
-
19
- 1. **Git 差异管理**
20
- - 读取当前 Git 仓库的变更内容(diff)
21
- - 支持暂存区和工作区的差异提取
22
-
23
- 2. **大模型调用**
24
- - 调用外部大语言模型 API 生成提交信息(OpenAI 兼容格式)
25
- - 支持从环境变量读取模型配置:
26
- - `LLM_API_KEY`:API 密钥
27
- - `LLM_ENDPOINT`:服务地址(例如 `https://api.openai.com/v1`)
28
- - `LLM_MODEL`:模型名称(例如 `gpt-4`、`gpt-3.5-turbo`)
29
-
30
- 3. **配置系统**
31
- - 支持 YAML 配置文件(如 `.git-repo-committer.yaml`)
32
- - 可配置项包括:
33
- - 模型选择与参数(model、temperature、max_tokens 等)
34
- - 生成风格或模板
35
- - Git 目录路径
36
-
37
- 4. **Git 提交**
38
- - 自动执行 `git commit` 操作
39
- - 使用生成的提交信息
40
-
41
- ### 环境变量
42
-
43
- 项目将依赖以下环境变量:
44
-
45
- - `LLM_API_KEY`:大模型 API 密钥
46
- - `LLM_ENDPOINT`:大模型服务地址(OpenAI 兼容端点)
47
- - `LLM_MODEL`:模型名称
48
-
49
- ## 项目结构
50
-
51
- ```
52
- git-repo-committer/
53
- ├── src/
54
- │ ├── index.ts # 入口文件
55
- │ ├── git.ts # Git 差异处理
56
- │ ├── llm.ts # 大模型调用(OpenAI 兼容)
57
- │ ├── config.ts # 配置读取
58
- │ └── commit.ts # 提交管理
59
- ├── config.yaml # YAML 配置文件
60
- ├── .env # 环境变量文件(不提交)
61
- ├── .env.example # 环境变量示例
62
- ├── .eslintrc.cjs # ESLint 配置
63
- ├── .prettierrc # Prettier 配置
64
- ├── tsconfig.json # TypeScript 配置
65
- ├── vite.config.ts # Vite 配置
66
- ├── package.json # 包描述文件
67
- ├── README.md # 项目说明
68
- └── .gitignore # Git 忽略规则
69
- ```
70
-
71
- ## 初始化步骤
72
-
73
- 1. **创建项目目录并初始化 npm**
74
-
75
- ```bash
76
- mkdir git-repo-committer
77
- cd git-repo-committer
78
- npm init -y
79
- ```
80
-
81
- 2. **初始化 TypeScript 配置**
82
-
83
- ```bash
84
- npm install --save-dev typescript
85
- npx tsc --init
86
- ```
87
-
88
- 3. **安装 Vite 及相关依赖**
89
-
90
- ```bash
91
- npm install --save-dev vite @types/node
92
- ```
93
-
94
- 4. **安装代码格式化工具**
95
-
96
- ```bash
97
- npm install --save-dev prettier eslint eslint-config-prettier @typescript-eslint/parser @typescript-eslint/eslint-plugin
98
- ```
99
-
100
- 5. **安装 Git 钩子工具**
101
-
102
- ```bash
103
- npm install --save-dev husky lint-staged
104
- npx husky init
105
- ```
106
-
107
- 6. **安装运行时依赖**
108
-
109
- ```bash
110
- npm install yaml dotenv openai
111
- ```
112
-
113
- 7. **创建配置文件**
114
-
115
- - 创建 `.env.example` 和 `.env`(写入环境变量)
116
- - 创建 `config.yaml`(定义模型参数和模板)
117
- - 创建 `.eslintrc.cjs`、`.prettierrc` 配置规则
118
- - 创建 `vite.config.ts` 定义构建目标
119
-
120
- 8. **实现核心模块**
121
-
122
- - `src/config.ts`:读取 YAML 配置和 `.env` 环境变量
123
- - `src/git.ts`:执行 `git diff` 命令并解析结果
124
- - `src/llm.ts`:使用 OpenAI SDK 调用兼容 API
125
- - `src/commit.ts`:组装并执行 `git commit -m "..."`
126
-
127
- 9. **完善 package.json 元数据**
128
-
129
-
130
- ## 发布计划
131
-
132
- 项目完成后将发布到 npm registry,作为命令行工具(CLI)供开发者使用。发布步骤:
133
-
134
- 1. 确保 `package.json` 中已填入正确的 GitHub 仓库地址和元信息
135
- 2. 运行 `npm run build` 构建产物
136
- 3. 执行 `npm publish` 发布
137
-
138
- ## 注意事项
139
-
140
- - 确保 `.gitignore` 包含 `node_modules`、`dist`、`.env` 等目录
141
- - 环境变量文件 `.env` 不应提交到版本控制系统
142
- - 使用 `openai` 包时需配置 `baseURL` 为 `LLM_ENDPOINT` 的值
143
- - 代码提交前会通过 husky + lint-staged 自动执行 ESLint 和 Prettier 格式化
package/src/commit.ts DELETED
@@ -1,12 +0,0 @@
1
- import { execSync } from "child_process";
2
-
3
- export function gitCommit(message: string, repoPath?: string): void {
4
- const cwd = repoPath || process.cwd();
5
- const escapedMessage = message.replace(/"/g, '\\"');
6
- execSync(`git commit -m "${escapedMessage}"`, { cwd, encoding: "utf-8" });
7
- }
8
-
9
- export function gitAddAll(repoPath?: string): void {
10
- const cwd = repoPath || process.cwd();
11
- execSync("git add -A", { cwd, encoding: "utf-8" });
12
- }
package/src/config.ts DELETED
@@ -1,74 +0,0 @@
1
- import { readFileSync, existsSync } from "fs";
2
- import { resolve } from "path";
3
- import YAML from "yaml";
4
- import dotenv from "dotenv";
5
-
6
- dotenv.config();
7
-
8
- export interface LLMConfig {
9
- model: string;
10
- temperature: number;
11
- max_tokens: number;
12
- }
13
-
14
- export interface StyleConfig {
15
- language: string;
16
- template: string;
17
- }
18
-
19
- export interface GitConfig {
20
- repoPath: string;
21
- }
22
-
23
- export interface AppConfig {
24
- llm: LLMConfig;
25
- style: StyleConfig;
26
- git: GitConfig;
27
- apiKey: string;
28
- endpoint: string;
29
- }
30
-
31
- const DEFAULT_CONFIG: AppConfig = {
32
- llm: {
33
- model: "deepseek-v4-flash",
34
- temperature: 0.7,
35
- max_tokens: 262144,
36
- },
37
- style: {
38
- language: "zh-CN",
39
- template: "conventional",
40
- },
41
- git: {
42
- repoPath: ".",
43
- },
44
- apiKey: "",
45
- endpoint: "https://api.openai.com/v1",
46
- };
47
-
48
- export function loadConfig(configPath?: string): AppConfig {
49
- const configFile =
50
- configPath ||
51
- [".git-repo-committer.yaml", ".git-repo-committer.yml", "config.yaml"].find(
52
- (f) => existsSync(resolve(process.cwd(), f)),
53
- );
54
-
55
- let fileConfig: Partial<AppConfig> = {};
56
-
57
- if (configFile) {
58
- const content = readFileSync(resolve(process.cwd(), configFile), "utf-8");
59
- fileConfig = YAML.parse(content);
60
- }
61
-
62
- return {
63
- ...DEFAULT_CONFIG,
64
- ...fileConfig,
65
- llm: { ...DEFAULT_CONFIG.llm, ...(fileConfig.llm || {}) },
66
- style: { ...DEFAULT_CONFIG.style, ...(fileConfig.style || {}) },
67
- git: { ...DEFAULT_CONFIG.git, ...(fileConfig.git || {}) },
68
- apiKey: process.env.LLM_API_KEY || fileConfig.apiKey || "",
69
- endpoint:
70
- process.env.LLM_ENDPOINT ||
71
- fileConfig.endpoint ||
72
- DEFAULT_CONFIG.endpoint,
73
- };
74
- }
package/src/git.ts DELETED
@@ -1,47 +0,0 @@
1
- import { execSync } from "child_process";
2
-
3
- export function getStagedDiff(repoPath?: string): string {
4
- const cwd = repoPath || process.cwd();
5
- try {
6
- return execSync("git diff --cached", { cwd, encoding: "utf-8" });
7
- } catch {
8
- return "";
9
- }
10
- }
11
-
12
- export function getUnstagedDiff(repoPath?: string): string {
13
- const cwd = repoPath || process.cwd();
14
- try {
15
- return execSync("git diff", { cwd, encoding: "utf-8" });
16
- } catch {
17
- return "";
18
- }
19
- }
20
-
21
- export function getAllDiff(repoPath?: string): string {
22
- const cwd = repoPath || process.cwd();
23
- const staged = getStagedDiff(cwd);
24
- const unstaged = getUnstagedDiff(cwd);
25
-
26
- const parts: string[] = [];
27
- if (staged.trim()) {
28
- parts.push("=== Staged Changes ===\n" + staged);
29
- }
30
- if (unstaged.trim()) {
31
- parts.push("=== Unstaged Changes ===\n" + unstaged);
32
- }
33
- return parts.join("\n\n");
34
- }
35
-
36
- export function hasStagedChanges(repoPath?: string): boolean {
37
- const cwd = repoPath || process.cwd();
38
- try {
39
- const result = execSync("git diff --cached --name-only", {
40
- cwd,
41
- encoding: "utf-8",
42
- });
43
- return result.trim().length > 0;
44
- } catch {
45
- return false;
46
- }
47
- }
package/src/index.ts DELETED
@@ -1,40 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { loadConfig } from "./config";
4
- import { getAllDiff, hasStagedChanges } from "./git";
5
- import { generateCommitMessage } from "./llm";
6
- import { gitCommit, gitAddAll } from "./commit";
7
-
8
- async function main() {
9
- const config = loadConfig();
10
-
11
- if (!config.apiKey) {
12
- console.error(
13
- "Error: LLM_API_KEY is not set. Please set it in .env or environment variables.",
14
- );
15
- process.exit(1);
16
- }
17
-
18
- if (!hasStagedChanges(config.git.repoPath)) {
19
- console.log("No staged changes found. Staging all changes...");
20
- gitAddAll(config.git.repoPath);
21
- }
22
-
23
- const diff = getAllDiff(config.git.repoPath);
24
- if (!diff.trim()) {
25
- console.log("No changes to commit.");
26
- process.exit(0);
27
- }
28
-
29
- console.log("Generating commit message...\n");
30
- const message = await generateCommitMessage(diff, config);
31
- console.log(`Commit message:\n ${message}\n`);
32
-
33
- gitCommit(message, config.git.repoPath);
34
- console.log("Commit successful!");
35
- }
36
-
37
- main().catch((err) => {
38
- console.error("Error:", err.message);
39
- process.exit(1);
40
- });
package/src/llm.ts DELETED
@@ -1,45 +0,0 @@
1
- import OpenAI from "openai";
2
- import type { AppConfig } from "./config";
3
-
4
- const SYSTEM_PROMPT = `你是一位擅长编写 Git 提交信息的专家。
5
- 根据提供的 Git diff,生成简洁且描述准确的提交信息。
6
- 遵循 Conventional Commits 格式:<type>(<scope>): <description>
7
- 类型包括:feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
8
- 标题行控制在 72 个字符以内。
9
- 如果有重要变更,在空行后添加更详细的正文说明。
10
- 只回复提交信息本身,不要添加任何解释。`;
11
-
12
- export async function generateCommitMessage(
13
- diff: string,
14
- config: AppConfig,
15
- ): Promise<string> {
16
- if (!config.apiKey) {
17
- throw new Error(
18
- "LLM_API_KEY is not set. Please set it in .env or environment variables.",
19
- );
20
- }
21
-
22
- const client = new OpenAI({
23
- apiKey: config.apiKey,
24
- baseURL: config.endpoint,
25
- });
26
-
27
- const response = await client.chat.completions.create({
28
- model: config.llm.model,
29
- temperature: config.llm.temperature,
30
- max_tokens: config.llm.max_tokens,
31
- messages: [
32
- { role: "system", content: SYSTEM_PROMPT },
33
- {
34
- role: "user",
35
- content: `以下是 Git diff 内容:\n\n${diff}`,
36
- },
37
- ],
38
- });
39
-
40
- const message = response.choices[0]?.message?.content?.trim();
41
- if (!message) {
42
- throw new Error("LLM returned an empty commit message.");
43
- }
44
- return message;
45
- }
package/tsconfig.json DELETED
@@ -1,18 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "strict": true,
7
- "esModuleInterop": true,
8
- "skipLibCheck": true,
9
- "forceConsistentCasingInFileNames": true,
10
- "resolveJsonModule": true,
11
- "declaration": true,
12
- "outDir": "./dist",
13
- "rootDir": "./src",
14
- "sourceMap": true
15
- },
16
- "include": ["src/**/*"],
17
- "exclude": ["node_modules", "dist"]
18
- }
package/vite.config.ts DELETED
@@ -1,18 +0,0 @@
1
- import { defineConfig } from "vite";
2
- import { resolve } from "path";
3
-
4
- export default defineConfig({
5
- build: {
6
- lib: {
7
- entry: resolve(__dirname, "src/index.ts"),
8
- name: "git-repo-comitter",
9
- fileName: "index",
10
- formats: ["cjs"],
11
- },
12
- outDir: "dist",
13
- sourcemap: true,
14
- rollupOptions: {
15
- external: ["openai", "yaml", "dotenv"],
16
- },
17
- },
18
- });