@ksw8954/git-ai-commit 1.0.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/AGENTS.md +38 -0
- package/CRUSH.md +28 -0
- package/Makefile +32 -0
- package/README.md +145 -0
- package/dist/commands/ai.d.ts +35 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +206 -0
- package/dist/commands/ai.js.map +1 -0
- package/dist/commands/commit.d.ts +17 -0
- package/dist/commands/commit.d.ts.map +1 -0
- package/dist/commands/commit.js +126 -0
- package/dist/commands/commit.js.map +1 -0
- package/dist/commands/config.d.ts +33 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +141 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/configCommand.d.ts +20 -0
- package/dist/commands/configCommand.d.ts.map +1 -0
- package/dist/commands/configCommand.js +108 -0
- package/dist/commands/configCommand.js.map +1 -0
- package/dist/commands/git.d.ts +26 -0
- package/dist/commands/git.d.ts.map +1 -0
- package/dist/commands/git.js +150 -0
- package/dist/commands/git.js.map +1 -0
- package/dist/commands/loadEnv.d.ts +2 -0
- package/dist/commands/loadEnv.d.ts.map +1 -0
- package/dist/commands/loadEnv.js +11 -0
- package/dist/commands/loadEnv.js.map +1 -0
- package/dist/commands/prCommand.d.ts +16 -0
- package/dist/commands/prCommand.d.ts.map +1 -0
- package/dist/commands/prCommand.js +61 -0
- package/dist/commands/prCommand.js.map +1 -0
- package/dist/commands/tag.d.ts +17 -0
- package/dist/commands/tag.d.ts.map +1 -0
- package/dist/commands/tag.js +127 -0
- package/dist/commands/tag.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/commit.d.ts +3 -0
- package/dist/prompts/commit.d.ts.map +1 -0
- package/dist/prompts/commit.js +101 -0
- package/dist/prompts/commit.js.map +1 -0
- package/dist/prompts/pr.d.ts +3 -0
- package/dist/prompts/pr.d.ts.map +1 -0
- package/dist/prompts/pr.js +58 -0
- package/dist/prompts/pr.js.map +1 -0
- package/dist/prompts/tag.d.ts +3 -0
- package/dist/prompts/tag.d.ts.map +1 -0
- package/dist/prompts/tag.js +42 -0
- package/dist/prompts/tag.js.map +1 -0
- package/eslint.config.js +35 -0
- package/jest.config.js +16 -0
- package/package.json +51 -0
- package/src/__tests__/ai.test.ts +185 -0
- package/src/__tests__/commitCommand.test.ts +155 -0
- package/src/__tests__/config.test.ts +238 -0
- package/src/__tests__/git.test.ts +88 -0
- package/src/__tests__/integration.test.ts +138 -0
- package/src/__tests__/prCommand.test.ts +121 -0
- package/src/__tests__/tagCommand.test.ts +197 -0
- package/src/commands/ai.ts +266 -0
- package/src/commands/commit.ts +215 -0
- package/src/commands/config.ts +182 -0
- package/src/commands/configCommand.ts +139 -0
- package/src/commands/git.ts +174 -0
- package/src/commands/history.ts +82 -0
- package/src/commands/loadEnv.ts +5 -0
- package/src/commands/log.ts +71 -0
- package/src/commands/prCommand.ts +108 -0
- package/src/commands/tag.ts +230 -0
- package/src/index.ts +29 -0
- package/src/prompts/commit.ts +105 -0
- package/src/prompts/pr.ts +64 -0
- package/src/prompts/tag.ts +48 -0
- package/tsconfig.json +19 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Repository Guidelines
|
|
2
|
+
|
|
3
|
+
## Project Structure & Module Organization
|
|
4
|
+
- `src/index.ts` bootstraps the CLI and wires subcommands.
|
|
5
|
+
- `src/commands/` houses command implementations; `src/prompts/` stores prompt templates.
|
|
6
|
+
- `src/__tests__/` contains Jest suites that mirror command modules.
|
|
7
|
+
- `dist/` holds compiled JavaScript, and `coverage/` stores Jest reports generated by CI or local runs.
|
|
8
|
+
- Configuration is centralized in `ConfigService`, which reads env vars such as `OPENAI_API_KEY` (and supports `AI_API_KEY`).
|
|
9
|
+
|
|
10
|
+
## Build, Test, and Development Commands
|
|
11
|
+
- `npm run build` compiles TypeScript into `dist/`.
|
|
12
|
+
- `npm run dev` runs the CLI via `ts-node` for rapid iteration.
|
|
13
|
+
- `npm run test` executes all Jest suites; add `:file` to target a single spec (e.g., `npm run test:file src/__tests__/commit.test.ts`).
|
|
14
|
+
- `npm run lint` applies the ESLint ruleset; `npm run typecheck` enforces strict typing without emitting files.
|
|
15
|
+
- `npm run test:coverage` produces coverage summaries under `coverage/`.
|
|
16
|
+
|
|
17
|
+
## Coding Style & Naming Conventions
|
|
18
|
+
- Stick to strict TypeScript with explicit return types; avoid `any`.
|
|
19
|
+
- Favor async/await for I/O, wrap fallible calls in `try/catch`, and surface descriptive errors.
|
|
20
|
+
- Indent with two spaces and group imports (stdlib, third-party, internal).
|
|
21
|
+
- Place new CLI features in `src/commands/` and associated prompt text in `src/prompts/`.
|
|
22
|
+
- Run `npm run lint` before pushing to guarantee ESLint compliance.
|
|
23
|
+
|
|
24
|
+
## Testing Guidelines
|
|
25
|
+
- Author Jest specs in `src/__tests__/` using the `*.test.ts` suffix.
|
|
26
|
+
- Organize tests with `describe` blocks per module and mock external services.
|
|
27
|
+
- Maintain at least 80% branch coverage; extend fixtures when adding command paths.
|
|
28
|
+
- Use `npm run test:watch` for iterative development and `npm run test:file` for focused checks.
|
|
29
|
+
|
|
30
|
+
## Commit & Pull Request Guidelines
|
|
31
|
+
- Write imperative, concise commit subjects (e.g., `Add staged diff validation`).
|
|
32
|
+
- Add a body when modifying configuration or integration points to capture reasoning.
|
|
33
|
+
- In PRs, link issues, summarize user impact, and attach CLI output or screenshots when UX changes.
|
|
34
|
+
- Verify `npm run lint`, `npm run test`, and `npm run build` locally before requesting review.
|
|
35
|
+
|
|
36
|
+
## Security & Configuration Tips
|
|
37
|
+
- Keep API keys (`OPENAI_API_KEY`, `AI_API_KEY`) in a local `.env`; never commit secrets.
|
|
38
|
+
- Route configuration reads and validation through `ConfigService` to ensure consistent defaults.
|
package/CRUSH.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Project Commands
|
|
2
|
+
- `npm run build` - Build TypeScript project
|
|
3
|
+
- `npm run dev` - Run in development mode
|
|
4
|
+
- `npm run test` - Run all tests
|
|
5
|
+
- `npm run test:file <path>` - Run single test file
|
|
6
|
+
- `npm run lint` - Run ESLint
|
|
7
|
+
- `npm run typecheck` - Run TypeScript type checking
|
|
8
|
+
- `npm link` - Install globally for CLI usage
|
|
9
|
+
|
|
10
|
+
# Environment Variables
|
|
11
|
+
- `OPENAI_API_KEY` or `AI_API_KEY` - API key for AI service
|
|
12
|
+
- `OPENAI_BASE_URL` or `AI_BASE_URL` - Custom API base URL (optional)
|
|
13
|
+
- `OPENAI_MODEL` or `AI_MODEL` - Model to use (optional, default: zai-org/GLM-4.5-FP8)
|
|
14
|
+
|
|
15
|
+
# Code Style Guidelines
|
|
16
|
+
- Use TypeScript with strict mode
|
|
17
|
+
- Follow ESLint configuration
|
|
18
|
+
- Use async/await for API calls
|
|
19
|
+
- Error handling with try/catch blocks
|
|
20
|
+
- Import style: use named imports for utilities, default for main exports
|
|
21
|
+
- Function naming: camelCase for functions, PascalCase for classes
|
|
22
|
+
- Use interfaces for type definitions
|
|
23
|
+
- CLI commands should be in src/commands/
|
|
24
|
+
- Prompts should be in src/prompts/
|
|
25
|
+
- Use proper TypeScript types for all function parameters and return values
|
|
26
|
+
- Class names should represent their purpose clearly
|
|
27
|
+
- Error messages should be descriptive and user-friendly
|
|
28
|
+
- Environment variable handling should be centralized in ConfigService
|
package/Makefile
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
.PHONY: install build dev lint test typecheck clean uninstall link unlink
|
|
2
|
+
|
|
3
|
+
install: ## Install dependencies and build the project
|
|
4
|
+
npm install
|
|
5
|
+
npm run build
|
|
6
|
+
|
|
7
|
+
build: ## Compile TypeScript sources
|
|
8
|
+
npm run build
|
|
9
|
+
|
|
10
|
+
dev: ## Run the CLI via ts-node in dev mode
|
|
11
|
+
npm run dev -- commit
|
|
12
|
+
|
|
13
|
+
lint: ## Run ESLint
|
|
14
|
+
npm run lint
|
|
15
|
+
|
|
16
|
+
test: ## Run Jest test suite
|
|
17
|
+
npm run test
|
|
18
|
+
|
|
19
|
+
typecheck: ## Run TypeScript type checking
|
|
20
|
+
npm run typecheck
|
|
21
|
+
|
|
22
|
+
clean: ## Remove build and coverage artifacts
|
|
23
|
+
rm -rf dist coverage
|
|
24
|
+
|
|
25
|
+
uninstall: ## Remove installed dependencies and build outputs
|
|
26
|
+
rm -rf node_modules package-lock.json dist coverage
|
|
27
|
+
|
|
28
|
+
link: ## Link the CLI globally
|
|
29
|
+
npm link
|
|
30
|
+
|
|
31
|
+
unlink: ## Unlink the globally installed CLI
|
|
32
|
+
npm unlink -g git-ai-commit
|
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Git AI Commit
|
|
2
|
+
|
|
3
|
+
AI-powered CLI that generates conventional commit messages based on your staged Git diff.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# clone and enter the repository
|
|
9
|
+
git clone https://github.com/onaries/git-ai-commit.git
|
|
10
|
+
cd git-ai-commit
|
|
11
|
+
|
|
12
|
+
# install dependencies and compile TypeScript
|
|
13
|
+
npm install
|
|
14
|
+
npm run build
|
|
15
|
+
|
|
16
|
+
# optional: link globally to use the CLI anywhere
|
|
17
|
+
npm link
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
If the package is published to npm, it can be installed directly in another project:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install git-ai-commit
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
After linking globally (`npm link`) or installing via npm, run:
|
|
29
|
+
|
|
30
|
+
### Commit Messages
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# generate a commit message from staged changes and confirm before committing
|
|
34
|
+
git-ai-commit commit
|
|
35
|
+
|
|
36
|
+
# print only the generated message without touching git
|
|
37
|
+
git-ai-commit commit --message-only
|
|
38
|
+
|
|
39
|
+
# pass extra instructions to guide the AI (appended to the system prompt)
|
|
40
|
+
git-ai-commit commit --prompt "docs 변경은 docs 타입으로, 패키지명은 scope로 포함해줘"
|
|
41
|
+
|
|
42
|
+
# override API settings for a single run
|
|
43
|
+
git-ai-commit commit --api-key <key> --base-url <url> --model <model>
|
|
44
|
+
|
|
45
|
+
# create and push the commit in one flow (will prompt for confirmation first)
|
|
46
|
+
git-ai-commit commit --push
|
|
47
|
+
|
|
48
|
+
# combine with message-only to preview with custom guidance
|
|
49
|
+
git-ai-commit commit --message-only --prompt "스코프는 패키지 디렉터리명으로 설정"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The command previews the AI-generated message, then asks `Proceed with git commit? (y/n)` before creating the commit. Use `--push` to push after a successful commit, or set auto push through the config command (see below). You can also provide additional instructions for this run using `--prompt "<text>"`; the text is appended to the AI's system prompt to guide the style/content.
|
|
53
|
+
|
|
54
|
+
During development you can run the CLI without building by using the dev script:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm run dev -- commit
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Pull Request Messages
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# create a PR title and body by diffing two branches
|
|
64
|
+
git-ai-commit pr --base main --compare feature/add-cache
|
|
65
|
+
|
|
66
|
+
# override API settings for the PR run only
|
|
67
|
+
git-ai-commit pr --base release --compare hotfix/urgent --api-key <key>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The PR command compares the Git diff from the base branch to the compare branch and prints a ready-to-paste pull request title with `## Summary` and `## Testing` sections in your configured language.
|
|
71
|
+
|
|
72
|
+
### Tags
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# create an annotated tag with a manual message (skips AI)
|
|
76
|
+
git-ai-commit tag v1.2.3 --message "Release notes"
|
|
77
|
+
|
|
78
|
+
# generate release notes from commit history since a base tag
|
|
79
|
+
git-ai-commit tag v1.3.0 --base-tag v1.2.3
|
|
80
|
+
|
|
81
|
+
# guide the AI with additional instructions for this tag
|
|
82
|
+
git-ai-commit tag v1.4.0 --prompt "사용자 기능/버그 수정/유지 보수로 묶고 한국어로 간결히"
|
|
83
|
+
|
|
84
|
+
# you can combine both
|
|
85
|
+
git-ai-commit tag v1.5.0 --base-tag v1.4.0 --prompt "docs는 별도 섹션, breaking change 강조"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
When AI generation is used, the CLI previews the tag message and asks for confirmation before creating the tag:
|
|
89
|
+
- `Create annotated tag <name>? (y/n)`
|
|
90
|
+
- After creation, it asks whether to push: `Push tag <name> to remote? (y/n)`
|
|
91
|
+
|
|
92
|
+
Providing `--message` uses your text verbatim but still asks for tag creation confirmation.
|
|
93
|
+
|
|
94
|
+
## Configuration
|
|
95
|
+
|
|
96
|
+
Persist defaults without exporting environment variables through the interactive config command:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
git-ai-commit config --show # display merged configuration
|
|
100
|
+
git-ai-commit config --language en # set default AI output language
|
|
101
|
+
git-ai-commit config --auto-push # push automatically after confirmed commits
|
|
102
|
+
git-ai-commit config --no-auto-push # disable automatic pushing
|
|
103
|
+
git-ai-commit config -k sk-... # store API key securely on disk
|
|
104
|
+
git-ai-commit config -b https://api.test # set a custom API base URL
|
|
105
|
+
git-ai-commit config --model gpt-4o-mini # set preferred model
|
|
106
|
+
git-ai-commit config --mode openai # prefer OPENAI_* environment variables
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The stored configuration works alongside environment variables—CLI flags override config values, which in turn override `.env` settings.
|
|
110
|
+
|
|
111
|
+
Configuration is written to `~/.git-ai-commit/config.json` by default. Set `GIT_AI_COMMIT_CONFIG_PATH=/custom/path.json` to use a different location.
|
|
112
|
+
|
|
113
|
+
## Environment Variables
|
|
114
|
+
|
|
115
|
+
Set the following variables (e.g., in a local `.env` file) before using the CLI:
|
|
116
|
+
|
|
117
|
+
- `AI_MODE` controls which provider defaults to: `openai` prioritises `OPENAI_*` vars; any other value (or unset) uses the `AI_*` vars first and falls back to `OPENAI_*`.
|
|
118
|
+
- Credentials: `AI_API_KEY` or `OPENAI_API_KEY`.
|
|
119
|
+
- Base URLs: `AI_BASE_URL` or `OPENAI_BASE_URL` (priority matches the selected mode).
|
|
120
|
+
- Models: `AI_MODEL` or `OPENAI_MODEL` (priority matches the selected mode).
|
|
121
|
+
|
|
122
|
+
## Development Commands
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
npm run lint # run ESLint with the repository rules
|
|
126
|
+
npm run test # execute the Jest suite
|
|
127
|
+
npm run test:watch # watch mode for tests
|
|
128
|
+
npm run typecheck # TypeScript type checking without emit
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### History
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# show all history (most recent last)
|
|
135
|
+
git-ai-commit history
|
|
136
|
+
|
|
137
|
+
# show last N entries
|
|
138
|
+
git-ai-commit history --limit 20
|
|
139
|
+
|
|
140
|
+
# output as JSON
|
|
141
|
+
git-ai-commit history --json --limit 10
|
|
142
|
+
|
|
143
|
+
# clear all history (asks for confirmation)
|
|
144
|
+
git-ai-commit history --clear
|
|
145
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { SupportedLanguage } from './config';
|
|
2
|
+
export interface AIServiceConfig {
|
|
3
|
+
apiKey: string;
|
|
4
|
+
baseURL?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
language?: SupportedLanguage;
|
|
7
|
+
verbose?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface CommitGenerationResult {
|
|
10
|
+
success: boolean;
|
|
11
|
+
message?: string;
|
|
12
|
+
error?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface TagGenerationResult {
|
|
15
|
+
success: boolean;
|
|
16
|
+
notes?: string;
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface PullRequestGenerationResult {
|
|
20
|
+
success: boolean;
|
|
21
|
+
message?: string;
|
|
22
|
+
error?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare class AIService {
|
|
25
|
+
private openai;
|
|
26
|
+
private model;
|
|
27
|
+
private language;
|
|
28
|
+
private verbose;
|
|
29
|
+
constructor(config: AIServiceConfig);
|
|
30
|
+
private debugLog;
|
|
31
|
+
generateCommitMessage(diff: string, extraInstructions?: string): Promise<CommitGenerationResult>;
|
|
32
|
+
generateTagNotes(tagName: string, commitLog: string): Promise<TagGenerationResult>;
|
|
33
|
+
generatePullRequestMessage(baseBranch: string, compareBranch: string, diff: string): Promise<PullRequestGenerationResult>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=ai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/commands/ai.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,OAAO,CAAU;gBAEb,MAAM,EAAE,eAAe;IAUnC,OAAO,CAAC,QAAQ;IAMV,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAkGhG,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAmDlF,0BAA0B,CAC9B,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,2BAA2B,CAAC;CAsDxC"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AIService = void 0;
|
|
7
|
+
const openai_1 = __importDefault(require("openai"));
|
|
8
|
+
const commit_1 = require("../prompts/commit");
|
|
9
|
+
const tag_1 = require("../prompts/tag");
|
|
10
|
+
const pr_1 = require("../prompts/pr");
|
|
11
|
+
class AIService {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.openai = new openai_1.default({
|
|
14
|
+
apiKey: config.apiKey,
|
|
15
|
+
baseURL: config.baseURL
|
|
16
|
+
});
|
|
17
|
+
this.model = config.model || 'zai-org/GLM-4.5-FP8';
|
|
18
|
+
this.language = config.language || 'ko';
|
|
19
|
+
this.verbose = config.verbose ?? true;
|
|
20
|
+
}
|
|
21
|
+
debugLog(...args) {
|
|
22
|
+
if (this.verbose) {
|
|
23
|
+
console.log(...args);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async generateCommitMessage(diff, extraInstructions) {
|
|
27
|
+
try {
|
|
28
|
+
this.debugLog('Sending request to AI API...');
|
|
29
|
+
this.debugLog('Model:', this.model);
|
|
30
|
+
this.debugLog('Base URL:', this.openai.baseURL);
|
|
31
|
+
const customInstructions = extraInstructions && extraInstructions.trim().length > 0
|
|
32
|
+
? `Git diff will be provided separately in the user message.\n\n## Additional User Instructions\n${extraInstructions.trim()}`
|
|
33
|
+
: 'Git diff will be provided separately in the user message.';
|
|
34
|
+
const response = await this.openai.chat.completions.create({
|
|
35
|
+
model: this.model,
|
|
36
|
+
messages: [
|
|
37
|
+
{
|
|
38
|
+
role: 'system',
|
|
39
|
+
content: (0, commit_1.generateCommitPrompt)('', customInstructions, this.language)
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
role: 'user',
|
|
43
|
+
content: `Git diff:\n${diff}`
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
max_tokens: 3000,
|
|
47
|
+
temperature: 0.1
|
|
48
|
+
});
|
|
49
|
+
this.debugLog('API Response received:', JSON.stringify(response, null, 2));
|
|
50
|
+
const choice = response.choices[0];
|
|
51
|
+
const message = choice?.message?.content?.trim();
|
|
52
|
+
// Handle reasoning content if available (type assertion for custom API response)
|
|
53
|
+
const messageAny = choice?.message;
|
|
54
|
+
const reasoningMessage = messageAny?.reasoning_content?.trim();
|
|
55
|
+
// Try to extract commit message from reasoning content if regular content is null
|
|
56
|
+
let finalMessage = message;
|
|
57
|
+
if (!finalMessage && reasoningMessage) {
|
|
58
|
+
// Look for commit message pattern in reasoning content
|
|
59
|
+
const commitMatch = reasoningMessage.match(/(?:feat|fix|docs|style|refactor|test|chore|build|ci|perf|revert): .+/);
|
|
60
|
+
if (commitMatch) {
|
|
61
|
+
finalMessage = commitMatch[0].trim();
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Look for any line that starts with conventional commit types
|
|
65
|
+
const typeMatch = reasoningMessage.match(/(?:feat|fix|docs|style|refactor|test|chore|build|ci|perf|revert)[^:]*: .+/);
|
|
66
|
+
if (typeMatch) {
|
|
67
|
+
finalMessage = typeMatch[0].trim();
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// Try to find a short descriptive line
|
|
71
|
+
const lines = reasoningMessage.split('\n').filter((line) => line.trim().length > 0);
|
|
72
|
+
const shortLine = lines.find((line) => line.length < 100 && line.includes('version'));
|
|
73
|
+
finalMessage = shortLine ? `chore: ${shortLine.trim()}` : `chore: update files`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!finalMessage) {
|
|
78
|
+
this.debugLog('No message found in response');
|
|
79
|
+
return {
|
|
80
|
+
success: false,
|
|
81
|
+
error: 'No commit message generated'
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Clean up the message
|
|
85
|
+
finalMessage = finalMessage.replace(/^(The commit message is:|Commit message:|Message:)\s*/, '');
|
|
86
|
+
// Ensure it follows conventional commit format
|
|
87
|
+
if (!finalMessage.match(/^(feat|fix|docs|style|refactor|test|chore|build|ci|perf|revert)(\(.+\))?!?: .+/)) {
|
|
88
|
+
// If it doesn't match the format, try to fix it
|
|
89
|
+
if (finalMessage.includes('version') || finalMessage.includes('update')) {
|
|
90
|
+
finalMessage = `chore: ${finalMessage}`;
|
|
91
|
+
}
|
|
92
|
+
else if (finalMessage.includes('feature') || finalMessage.includes('add')) {
|
|
93
|
+
finalMessage = `feat: ${finalMessage}`;
|
|
94
|
+
}
|
|
95
|
+
else if (finalMessage.includes('fix') || finalMessage.includes('bug')) {
|
|
96
|
+
finalMessage = `fix: ${finalMessage}`;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
finalMessage = `chore: ${finalMessage}`;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
success: true,
|
|
104
|
+
message: finalMessage
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
console.error('API Error:', error);
|
|
109
|
+
return {
|
|
110
|
+
success: false,
|
|
111
|
+
error: error instanceof Error ? error.message : 'Failed to generate commit message'
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async generateTagNotes(tagName, commitLog) {
|
|
116
|
+
try {
|
|
117
|
+
this.debugLog('Sending request to AI API for tag notes...');
|
|
118
|
+
this.debugLog('Model:', this.model);
|
|
119
|
+
this.debugLog('Base URL:', this.openai.baseURL);
|
|
120
|
+
const response = await this.openai.chat.completions.create({
|
|
121
|
+
model: this.model,
|
|
122
|
+
messages: [
|
|
123
|
+
{
|
|
124
|
+
role: 'system',
|
|
125
|
+
content: (0, tag_1.generateTagPrompt)(tagName, '', this.language)
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
role: 'user',
|
|
129
|
+
content: `Commit log:\n${commitLog}`
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
max_tokens: 3000,
|
|
133
|
+
temperature: 0.2
|
|
134
|
+
});
|
|
135
|
+
const choice = response.choices[0];
|
|
136
|
+
const message = choice?.message?.content?.trim();
|
|
137
|
+
const messageAny = choice?.message;
|
|
138
|
+
const reasoningMessage = messageAny?.reasoning_content?.trim();
|
|
139
|
+
const finalNotes = message || reasoningMessage;
|
|
140
|
+
if (!finalNotes) {
|
|
141
|
+
this.debugLog('No notes found in response');
|
|
142
|
+
return {
|
|
143
|
+
success: false,
|
|
144
|
+
error: 'No tag notes generated'
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
success: true,
|
|
149
|
+
notes: finalNotes.trim()
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
console.error('API Error:', error);
|
|
154
|
+
return {
|
|
155
|
+
success: false,
|
|
156
|
+
error: error instanceof Error ? error.message : 'Failed to generate tag notes'
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async generatePullRequestMessage(baseBranch, compareBranch, diff) {
|
|
161
|
+
try {
|
|
162
|
+
this.debugLog('Sending request to AI API for pull request message...');
|
|
163
|
+
this.debugLog('Model:', this.model);
|
|
164
|
+
this.debugLog('Base URL:', this.openai.baseURL);
|
|
165
|
+
const response = await this.openai.chat.completions.create({
|
|
166
|
+
model: this.model,
|
|
167
|
+
messages: [
|
|
168
|
+
{
|
|
169
|
+
role: 'system',
|
|
170
|
+
content: (0, pr_1.generatePullRequestPrompt)(baseBranch, compareBranch, '', this.language)
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
role: 'user',
|
|
174
|
+
content: `Git diff between ${baseBranch} and ${compareBranch}:\n${diff}`
|
|
175
|
+
}
|
|
176
|
+
],
|
|
177
|
+
max_tokens: 4000,
|
|
178
|
+
temperature: 0.2
|
|
179
|
+
});
|
|
180
|
+
const choice = response.choices[0];
|
|
181
|
+
const message = choice?.message?.content?.trim();
|
|
182
|
+
const messageAny = choice?.message;
|
|
183
|
+
const reasoningMessage = messageAny?.reasoning_content?.trim();
|
|
184
|
+
const finalMessage = message || reasoningMessage;
|
|
185
|
+
if (!finalMessage) {
|
|
186
|
+
return {
|
|
187
|
+
success: false,
|
|
188
|
+
error: 'No pull request message generated'
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
success: true,
|
|
193
|
+
message: finalMessage.trim()
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
console.error('API Error:', error);
|
|
198
|
+
return {
|
|
199
|
+
success: false,
|
|
200
|
+
error: error instanceof Error ? error.message : 'Failed to generate pull request message'
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
exports.AIService = AIService;
|
|
206
|
+
//# sourceMappingURL=ai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai.js","sourceRoot":"","sources":["../../src/commands/ai.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export interface CommitOptions {
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
baseURL?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
push?: boolean;
|
|
7
|
+
messageOnly?: boolean;
|
|
8
|
+
prompt?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class CommitCommand {
|
|
11
|
+
private program;
|
|
12
|
+
constructor();
|
|
13
|
+
private handleCommit;
|
|
14
|
+
private confirmCommit;
|
|
15
|
+
getCommand(): Command;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=commit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit.d.ts","sourceRoot":"","sources":["../../src/commands/commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAU;;YAcX,YAAY;YAuGZ,aAAa;IAgB3B,UAAU,IAAI,OAAO;CAGtB"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CommitCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const readline_1 = __importDefault(require("readline"));
|
|
9
|
+
const git_1 = require("./git");
|
|
10
|
+
const ai_1 = require("./ai");
|
|
11
|
+
const config_1 = require("./config");
|
|
12
|
+
class CommitCommand {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.program = new commander_1.Command('commit')
|
|
15
|
+
.description('Generate AI-powered commit message')
|
|
16
|
+
.option('-k, --api-key <key>', 'OpenAI API key (overrides env var)')
|
|
17
|
+
.option('-b, --base-url <url>', 'Custom API base URL (overrides env var)')
|
|
18
|
+
.option('--model <model>', 'Model to use (overrides env var)')
|
|
19
|
+
.option('-m, --message-only', 'Output only the generated commit message and skip git actions')
|
|
20
|
+
.option('-p, --push', 'Push current branch after creating the commit (implies --commit)')
|
|
21
|
+
.option('--prompt <text>', 'Additional instructions to append to the AI prompt for this commit')
|
|
22
|
+
.action(this.handleCommit.bind(this));
|
|
23
|
+
}
|
|
24
|
+
async handleCommit(options) {
|
|
25
|
+
try {
|
|
26
|
+
const existingConfig = config_1.ConfigService.getConfig();
|
|
27
|
+
const mergedApiKey = options.apiKey || existingConfig.apiKey;
|
|
28
|
+
const mergedBaseURL = options.baseURL || existingConfig.baseURL;
|
|
29
|
+
const mergedModel = options.model || existingConfig.model;
|
|
30
|
+
const messageOnly = Boolean(options.messageOnly);
|
|
31
|
+
const log = (...args) => {
|
|
32
|
+
if (!messageOnly) {
|
|
33
|
+
console.log(...args);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
config_1.ConfigService.validateConfig({
|
|
37
|
+
apiKey: mergedApiKey,
|
|
38
|
+
language: existingConfig.language
|
|
39
|
+
});
|
|
40
|
+
const aiConfig = {
|
|
41
|
+
apiKey: mergedApiKey,
|
|
42
|
+
baseURL: mergedBaseURL,
|
|
43
|
+
model: mergedModel,
|
|
44
|
+
language: existingConfig.language,
|
|
45
|
+
verbose: !messageOnly
|
|
46
|
+
};
|
|
47
|
+
log('Getting staged changes...');
|
|
48
|
+
const diffResult = await git_1.GitService.getStagedDiff();
|
|
49
|
+
if (!diffResult.success) {
|
|
50
|
+
console.error('Error:', diffResult.error);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
log('Generating commit message...');
|
|
54
|
+
const aiService = new ai_1.AIService(aiConfig);
|
|
55
|
+
const aiResult = await aiService.generateCommitMessage(diffResult.diff, options.prompt);
|
|
56
|
+
if (!aiResult.success) {
|
|
57
|
+
console.error('Error:', aiResult.error);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
if (typeof aiResult.message !== 'string') {
|
|
61
|
+
console.error('Error: Failed to generate commit message');
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
if (messageOnly) {
|
|
65
|
+
console.log(aiResult.message);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
console.log('\nGenerated commit message:');
|
|
69
|
+
console.log(aiResult.message);
|
|
70
|
+
const confirmed = await this.confirmCommit();
|
|
71
|
+
if (!confirmed) {
|
|
72
|
+
console.log('Commit cancelled by user.');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
console.log('\nCreating commit...');
|
|
76
|
+
const commitSuccess = await git_1.GitService.createCommit(aiResult.message);
|
|
77
|
+
if (commitSuccess) {
|
|
78
|
+
console.log('✅ Commit created successfully!');
|
|
79
|
+
const pushRequested = Boolean(options.push);
|
|
80
|
+
const pushFromConfig = !pushRequested && existingConfig.autoPush;
|
|
81
|
+
const shouldPush = pushRequested || pushFromConfig;
|
|
82
|
+
if (shouldPush) {
|
|
83
|
+
if (pushFromConfig) {
|
|
84
|
+
console.log('Auto push enabled in config; pushing to remote...');
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
console.log('Pushing to remote...');
|
|
88
|
+
}
|
|
89
|
+
const pushSuccess = await git_1.GitService.push();
|
|
90
|
+
if (pushSuccess) {
|
|
91
|
+
console.log('✅ Push completed successfully!');
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
console.error('❌ Failed to push to remote');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
console.error('❌ Failed to create commit');
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async confirmCommit() {
|
|
110
|
+
const rl = readline_1.default.createInterface({
|
|
111
|
+
input: process.stdin,
|
|
112
|
+
output: process.stdout
|
|
113
|
+
});
|
|
114
|
+
const answer = await new Promise(resolve => {
|
|
115
|
+
rl.question('Proceed with git commit? (y/n): ', resolve);
|
|
116
|
+
});
|
|
117
|
+
rl.close();
|
|
118
|
+
const normalized = answer.trim().toLowerCase();
|
|
119
|
+
return normalized === 'y' || normalized === 'yes';
|
|
120
|
+
}
|
|
121
|
+
getCommand() {
|
|
122
|
+
return this.program;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.CommitCommand = CommitCommand;
|
|
126
|
+
//# sourceMappingURL=commit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit.js","sourceRoot":"","sources":["../../src/commands/commit.ts"],"names":[],"mappings":"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"}
|