mirror of
https://github.com/di-sukharev/opencommit.git
synced 2026-01-13 07:38:01 -05:00
Compare commits
100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e447575980 | ||
|
|
ffebbc6e1b | ||
|
|
dab0f58d14 | ||
|
|
226e21c28f | ||
|
|
0bb89abccc | ||
|
|
ad70a90b1f | ||
|
|
4deaf56e5a | ||
|
|
7c1fc10248 | ||
|
|
0c25a9e32c | ||
|
|
3f5df6ef7c | ||
|
|
6cb85e40e9 | ||
|
|
ba82d4d476 | ||
|
|
9bf2ed34a5 | ||
|
|
f6ab25ed1b | ||
|
|
83abd5ffd6 | ||
|
|
42c26cbaaa | ||
|
|
51613c2aea | ||
|
|
f04757f8af | ||
|
|
70f048672c | ||
|
|
a8a548ba5a | ||
|
|
eb09d5f4f6 | ||
|
|
801f6a9e7a | ||
|
|
b4f1bbdfe0 | ||
|
|
1ecad09e44 | ||
|
|
c57b5e394d | ||
|
|
8100d9beb8 | ||
|
|
84997faea2 | ||
|
|
8f60345008 | ||
|
|
c148048452 | ||
|
|
add8855bf9 | ||
|
|
0cc5be10f2 | ||
|
|
30d2d9d284 | ||
|
|
d69fa6c2d7 | ||
|
|
bf3b8c6ded | ||
|
|
f851ea1fff | ||
|
|
d6cbaf5f5f | ||
|
|
220d0b292f | ||
|
|
e5d3c8d4ff | ||
|
|
cbc8d61f99 | ||
|
|
7fd357e78e | ||
|
|
5837d1fa2e | ||
|
|
36f282d8a5 | ||
|
|
9f65c450e3 | ||
|
|
d5f53fec5a | ||
|
|
b6651a4c47 | ||
|
|
2b10dc089c | ||
|
|
a5e60ac23c | ||
|
|
e519752938 | ||
|
|
1ba5e20228 | ||
|
|
4103bafc4f | ||
|
|
5a9b460033 | ||
|
|
3364289034 | ||
|
|
5185f3365c | ||
|
|
17ed061f73 | ||
|
|
06fa6daa72 | ||
|
|
af457473be | ||
|
|
33b418e399 | ||
|
|
7e5ed6de0b | ||
|
|
6ba0f97163 | ||
|
|
0d559d4499 | ||
|
|
686f876cb0 | ||
|
|
acf3e450ae | ||
|
|
8be30a734d | ||
|
|
e2f68b7256 | ||
|
|
eacc750952 | ||
|
|
3fe57537ad | ||
|
|
db9cff1ae1 | ||
|
|
1c29b91408 | ||
|
|
425eeef732 | ||
|
|
52c396eb16 | ||
|
|
f5bcf58f7b | ||
|
|
4b53a08653 | ||
|
|
95d3d8b6c9 | ||
|
|
2c79bf22df | ||
|
|
e8c1a75a46 | ||
|
|
5d064ac873 | ||
|
|
8d01829a9b | ||
|
|
e9c66ae168 | ||
|
|
18b0004b81 | ||
|
|
4d4157087e | ||
|
|
3edb6e2fc1 | ||
|
|
d428102a67 | ||
|
|
9404f5d410 | ||
|
|
8c1eb4a5ad | ||
|
|
bafe7e9ede | ||
|
|
a4716b35a4 | ||
|
|
c1e9062ce0 | ||
|
|
c7efa6f935 | ||
|
|
1b70de1d20 | ||
|
|
853662acc4 | ||
|
|
0e1ad33179 | ||
|
|
e7eaa5425e | ||
|
|
4b96670374 | ||
|
|
e128cdece1 | ||
|
|
4cc73208cd | ||
|
|
ea864d18f4 | ||
|
|
5d131e66fa | ||
|
|
bf24be92a1 | ||
|
|
3103ae18b8 | ||
|
|
7c9feba3ba |
91
.github/ISSUE_TEMPLATE/bug.yaml
vendored
Normal file
91
.github/ISSUE_TEMPLATE/bug.yaml
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
name: 🐞 Bug Report
|
||||
description: File a bug report
|
||||
title: "[Bug]: "
|
||||
labels: ["bug", "triage"]
|
||||
assignees:
|
||||
- octocat
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
- type: input
|
||||
id: opencommit-version
|
||||
attributes:
|
||||
label: Opencommit Version
|
||||
description: What version of our software are you running?
|
||||
placeholder: ex. 1.1.22
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: node-version
|
||||
attributes:
|
||||
label: Node Version
|
||||
description: What version of node are you running?
|
||||
placeholder: ex. 19.8.1
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: npm-version
|
||||
attributes:
|
||||
label: NPM Version
|
||||
description: What version of npm are you running?
|
||||
placeholder: ex. 9.6.2
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: OS
|
||||
attributes:
|
||||
label: What OS are you seeing the problem on?
|
||||
multiple: true
|
||||
options:
|
||||
- Mac
|
||||
- Windows
|
||||
- Other Linux Distro
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Tell us what you see!
|
||||
value: "A bug happened!"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Tell us what you expected to happen!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: current-behavior
|
||||
attributes:
|
||||
label: Current Behavior
|
||||
description: Also tell us, what is currently happening?
|
||||
placeholder: Tell us what is happening now.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: possible-solution
|
||||
attributes:
|
||||
label: Possible Solution
|
||||
description: Do you have a solution for the issue?
|
||||
placeholder: Tell us what the solution could look like.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: steps-to-reproduce
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: Tell us how to reproduce the issue?
|
||||
placeholder: Tell us how to reproduce the issue?
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
48
.github/ISSUE_TEMPLATE/featureRequest.yaml
vendored
Normal file
48
.github/ISSUE_TEMPLATE/featureRequest.yaml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
name: 🛠️ Feature Request
|
||||
description: Suggest an idea to help us improve Opencommit
|
||||
title: "[Feature]: "
|
||||
labels:
|
||||
- "feature_request"
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**Thanks :heart: for taking the time to fill out this feature request report!**
|
||||
We kindly ask that you search to see if an issue [already exists](https://github.com/di-sukharev/opencommit/issues?q=is%3Aissue+sort%3Acreated-desc+) for your feature.
|
||||
|
||||
We are also happy to accept contributions from our users. For more details see [here](https://github.com/di-sukharev/opencommit/blob/master/.github/CONTRIBUTING.md).
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: |
|
||||
A clear and concise description of the feature you're interested in.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Suggested Solution
|
||||
description: |
|
||||
Describe the solution you'd like. A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Alternatives
|
||||
description: |
|
||||
Describe alternatives you've considered.
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: |
|
||||
Add any other context about the problem here.
|
||||
validations:
|
||||
required: false
|
||||
1
.github/TODO.md
vendored
1
.github/TODO.md
vendored
@@ -8,3 +8,4 @@
|
||||
- [x] batch small files in one request
|
||||
- [] add tests
|
||||
- [] optimize prompt, maybe no prompt would be cleaner
|
||||
- [] try setting max commit msg length, maybe it will make commits short and more concise
|
||||
|
||||
BIN
.github/opencommit-example.png
vendored
BIN
.github/opencommit-example.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 318 KiB After Width: | Height: | Size: 304 KiB |
76
.github/workflows/codeql.yml
vendored
Normal file
76
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "master" ]
|
||||
schedule:
|
||||
- cron: '21 16 * * 0'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Use only 'java' to analyze code written in Java, Kotlin or both
|
||||
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
20
.github/workflows/dependency-review.yml
vendored
Normal file
20
.github/workflows/dependency-review.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
# Dependency Review Action
|
||||
#
|
||||
# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging.
|
||||
#
|
||||
# Source repository: https://github.com/actions/dependency-review-action
|
||||
# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
|
||||
name: 'Dependency Review'
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
dependency-review:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@v3
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@v2
|
||||
28
.github/workflows/stale.yml
vendored
Normal file
28
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
|
||||
#
|
||||
# You can adjust the behavior by modifying this file.
|
||||
# For more information, see:
|
||||
# https://github.com/actions/stale
|
||||
name: Mark stale issues and pull requests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '27 21 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 40
|
||||
stale-issue-message: 'Stale issue message'
|
||||
stale-pr-message: 'Stale pull request message'
|
||||
stale-issue-label: 'no-issue-activity'
|
||||
stale-pr-label: 'no-pr-activity'
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -11,4 +11,5 @@ logfile.log
|
||||
uncaughtExceptions.log
|
||||
.vscode
|
||||
src/*.json
|
||||
.idea
|
||||
.idea
|
||||
test.ts
|
||||
16
README.md
16
README.md
@@ -54,6 +54,18 @@ oc
|
||||
|
||||
## Features
|
||||
|
||||
### Switch to GPT-4
|
||||
|
||||
By default OpenCommit uses GPT-3.5-turbo (ChatGPT).
|
||||
|
||||
You may switch to GPT-4 which performs better, but costs ~x15 times more 🤠
|
||||
|
||||
```sh
|
||||
oc config set model=gpt-4
|
||||
```
|
||||
|
||||
Make sure you do lowercase `gpt-4`.
|
||||
|
||||
### Preface commits with emoji 🤠
|
||||
|
||||
[GitMoji](https://gitmoji.dev/) convention is used.
|
||||
@@ -99,6 +111,7 @@ oc config set language=fr
|
||||
oc config set language=French
|
||||
oc config set language=française
|
||||
```
|
||||
|
||||
The default language set is **English**
|
||||
All available languages are currently listed in the [i18n](https://github.com/di-sukharev/opencommit/tree/master/src/i18n) folder
|
||||
|
||||
@@ -117,6 +130,7 @@ git commit -m "${generatedMessage}" --no-verify
|
||||
```
|
||||
|
||||
### Ignore files
|
||||
|
||||
You can ignore files from submission to OpenAI by creating a `.opencommitignore` file. For example:
|
||||
|
||||
```ignorelang
|
||||
@@ -155,4 +169,4 @@ Or follow the process of your IDE Source Control feature, when it calls `git com
|
||||
|
||||
## Payments
|
||||
|
||||
You pay for your own requests to OpenAI API. OpenCommit uses ChatGPT official model, that is ~10x times cheaper than GPT-3 and ~6x times cheaper than GPT-4.
|
||||
You pay for your own requests to OpenAI API. OpenCommit uses ChatGPT (3.5-turbo) official model, that is ~15x times cheaper than GPT-4.
|
||||
|
||||
14
esbuild.config.js
Normal file
14
esbuild.config.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import { build } from 'esbuild'
|
||||
import fs from 'fs'
|
||||
|
||||
await build({
|
||||
entryPoints: ['./src/cli.ts'],
|
||||
bundle: true,
|
||||
platform: 'node',
|
||||
format: 'cjs',
|
||||
outfile: './out/cli.cjs',
|
||||
});
|
||||
|
||||
const wasmFile = fs.readFileSync('./node_modules/@dqbd/tiktoken/lite/tiktoken_bg.wasm')
|
||||
|
||||
fs.writeFileSync('./out/tiktoken_bg.wasm', wasmFile)
|
||||
11
package-lock.json
generated
11
package-lock.json
generated
@@ -1,15 +1,16 @@
|
||||
{
|
||||
"name": "opencommit",
|
||||
"version": "1.1.24",
|
||||
"version": "2.0.10",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "opencommit",
|
||||
"version": "1.1.24",
|
||||
"version": "2.0.10",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^0.6.1",
|
||||
"@dqbd/tiktoken": "^1.0.2",
|
||||
"axios": "^1.3.4",
|
||||
"chalk": "^5.2.0",
|
||||
"cleye": "^1.3.2",
|
||||
@@ -21,6 +22,7 @@
|
||||
},
|
||||
"bin": {
|
||||
"oc": "out/cli.cjs",
|
||||
"oco": "out/cli.cjs",
|
||||
"opencommit": "out/cli.cjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -83,6 +85,11 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@dqbd/tiktoken": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@dqbd/tiktoken/-/tiktoken-1.0.6.tgz",
|
||||
"integrity": "sha512-umSdeZTy/SbPPKVuZKV/XKyFPmXSN145CcM3iHjBbmhlohBJg7vaDp4cPCW+xNlWL6L2U1sp7T2BD+di2sUKdA=="
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "opencommit",
|
||||
"version": "1.1.24",
|
||||
"version": "2.0.10",
|
||||
"description": "GPT CLI to auto-generate impressive commits in 1 second. Killing lame commits with AI 🤯🔫",
|
||||
"keywords": [
|
||||
"git",
|
||||
@@ -17,7 +17,8 @@
|
||||
"main": "cli.js",
|
||||
"bin": {
|
||||
"opencommit": "./out/cli.cjs",
|
||||
"oc": "./out/cli.cjs"
|
||||
"oc": "./out/cli.cjs",
|
||||
"oco": "./out/cli.cjs"
|
||||
},
|
||||
"repository": {
|
||||
"url": "https://github.com/di-sukharev/opencommit"
|
||||
@@ -40,7 +41,7 @@
|
||||
"watch": "npm run -S build -- --sourcemap --watch",
|
||||
"start": "node ./out/cli.cjs",
|
||||
"dev": "ts-node ./src/cli.ts",
|
||||
"build": "rimraf out && esbuild ./src/cli.ts --bundle --outfile=out/cli.cjs --format=cjs --platform=node",
|
||||
"build": "rimraf out && node esbuild.config.js",
|
||||
"deploy": "npm run build && npm version patch && npm publish --tag latest",
|
||||
"lint": "eslint src --ext ts && tsc --noEmit",
|
||||
"format": "prettier --write src"
|
||||
@@ -60,6 +61,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^0.6.1",
|
||||
"@dqbd/tiktoken": "^1.0.2",
|
||||
"axios": "^1.3.4",
|
||||
"chalk": "^5.2.0",
|
||||
"cleye": "^1.3.2",
|
||||
|
||||
16
src/api.ts
16
src/api.ts
@@ -12,6 +12,8 @@ import { CONFIG_MODES, getConfig } from './commands/config';
|
||||
const config = getConfig();
|
||||
|
||||
let apiKey = config?.OPENAI_API_KEY;
|
||||
let basePath = config?.OPENAI_BASE_PATH;
|
||||
let maxTokens = config?.OPENAI_MAX_TOKENS;
|
||||
|
||||
const [command, mode] = process.argv.slice(2);
|
||||
|
||||
@@ -28,23 +30,31 @@ if (!apiKey && command !== 'config' && mode !== CONFIG_MODES.set) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const MODEL = config?.model || 'gpt-3.5-turbo';
|
||||
|
||||
class OpenAi {
|
||||
private openAiApiConfiguration = new OpenAiApiConfiguration({
|
||||
apiKey: apiKey
|
||||
});
|
||||
private openAI!: OpenAIApi;
|
||||
|
||||
private openAI = new OpenAIApi(this.openAiApiConfiguration);
|
||||
constructor() {
|
||||
if (basePath) {
|
||||
this.openAiApiConfiguration.basePath = basePath;
|
||||
}
|
||||
this.openAI = new OpenAIApi(this.openAiApiConfiguration);
|
||||
}
|
||||
|
||||
public generateCommitMessage = async (
|
||||
messages: Array<ChatCompletionRequestMessage>
|
||||
): Promise<string | undefined> => {
|
||||
try {
|
||||
const { data } = await this.openAI.createChatCompletion({
|
||||
model: 'gpt-3.5-turbo',
|
||||
model: MODEL,
|
||||
messages,
|
||||
temperature: 0,
|
||||
top_p: 0.1,
|
||||
max_tokens: 196
|
||||
max_tokens: maxTokens ?? 196
|
||||
});
|
||||
|
||||
const message = data.choices[0].message;
|
||||
|
||||
@@ -22,7 +22,8 @@ cli(
|
||||
},
|
||||
async () => {
|
||||
// await checkIsLatestVersion();
|
||||
if (isHookCalled) {
|
||||
|
||||
if (await isHookCalled()) {
|
||||
prepareCommitMessageHook();
|
||||
} else {
|
||||
commit(extraArgs);
|
||||
|
||||
@@ -22,10 +22,9 @@ import {
|
||||
import chalk from 'chalk';
|
||||
import { trytm } from '../utils/trytm';
|
||||
|
||||
// Adding a function to get the list of remotes
|
||||
const getGitRemotes = async () => {
|
||||
const { stdout } = await execa('git', ['remote']);
|
||||
return stdout.split('\n').filter((remote) => remote.trim() !== '');
|
||||
return stdout.split('\n').filter((remote) => Boolean(remote.trim()));
|
||||
};
|
||||
|
||||
const generateCommitMessageFromGitDiff = async (
|
||||
@@ -74,11 +73,18 @@ ${chalk.grey('——————————————————')}`
|
||||
...extraArgs
|
||||
]);
|
||||
|
||||
outro(`${chalk.green('✔')} successfully committed`);
|
||||
outro(`${chalk.green('✔')} Successfully committed`);
|
||||
|
||||
outro(stdout);
|
||||
|
||||
const remotes = await getGitRemotes();
|
||||
|
||||
if (!remotes.length) {
|
||||
const { stdout } = await execa('git', ['push']);
|
||||
if (stdout) outro(stdout);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (remotes.length === 1) {
|
||||
const isPushConfirmedByUser = await confirm({
|
||||
message: 'Do you want to run `git push`?'
|
||||
@@ -96,10 +102,13 @@ ${chalk.grey('——————————————————')}`
|
||||
]);
|
||||
|
||||
pushSpinner.stop(
|
||||
`${chalk.green('✔')} successfully pushed all commits to ${remotes[0]}`
|
||||
`${chalk.green('✔')} Successfully pushed all commits to ${remotes[0]}`
|
||||
);
|
||||
|
||||
if (stdout) outro(stdout);
|
||||
} else {
|
||||
outro('`git push` aborted');
|
||||
process.exit(0);
|
||||
}
|
||||
} else {
|
||||
const selectedRemote = (await select({
|
||||
@@ -117,7 +126,7 @@ ${chalk.grey('——————————————————')}`
|
||||
pushSpinner.stop(
|
||||
`${chalk.green(
|
||||
'✔'
|
||||
)} successfully pushed all commits to ${selectedRemote}`
|
||||
)} Successfully pushed all commits to ${selectedRemote}`
|
||||
);
|
||||
|
||||
if (stdout) outro(stdout);
|
||||
@@ -207,5 +216,6 @@ export async function commit(
|
||||
outro(`${chalk.red('✖')} ${generateCommitError}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
@@ -10,8 +10,11 @@ import { getI18nLocal } from '../i18n';
|
||||
|
||||
export enum CONFIG_KEYS {
|
||||
OPENAI_API_KEY = 'OPENAI_API_KEY',
|
||||
OPENAI_MAX_TOKENS = 'OPENAI_MAX_TOKENS',
|
||||
OPENAI_BASE_PATH = 'OPENAI_BASE_PATH',
|
||||
description = 'description',
|
||||
emoji = 'emoji',
|
||||
model = 'model',
|
||||
language = 'language'
|
||||
}
|
||||
|
||||
@@ -61,6 +64,16 @@ export const configValidators = {
|
||||
return value;
|
||||
},
|
||||
|
||||
[CONFIG_KEYS.OPENAI_MAX_TOKENS](value: any) {
|
||||
validateConfig(
|
||||
CONFIG_KEYS.OPENAI_MAX_TOKENS,
|
||||
typeof value === 'number',
|
||||
'Must be a number'
|
||||
);
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
[CONFIG_KEYS.emoji](value: any) {
|
||||
validateConfig(
|
||||
CONFIG_KEYS.emoji,
|
||||
@@ -78,6 +91,24 @@ export const configValidators = {
|
||||
`${value} is not supported yet`
|
||||
);
|
||||
return getI18nLocal(value);
|
||||
},
|
||||
|
||||
[CONFIG_KEYS.OPENAI_BASE_PATH](value: any) {
|
||||
validateConfig(
|
||||
CONFIG_KEYS.OPENAI_BASE_PATH,
|
||||
typeof value == 'string',
|
||||
`${value} is not supported yet`
|
||||
);
|
||||
return value;
|
||||
},
|
||||
|
||||
[CONFIG_KEYS.model](value: any) {
|
||||
validateConfig(
|
||||
CONFIG_KEYS.OPENAI_BASE_PATH,
|
||||
value === 'gpt-3.5-turbo' || value === 'gpt-4',
|
||||
`${value} is not supported yet, use 'gpt-4' or 'gpt-3.5-turbo' (default)`
|
||||
);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -128,7 +159,7 @@ export const setConfig = (keyValues: [key: string, value: string][]) => {
|
||||
|
||||
writeFileSync(configPath, iniStringify(config), 'utf8');
|
||||
|
||||
outro(`${chalk.green('✔')} config successfully set`);
|
||||
outro(`${chalk.green('✔')} Config successfully set`);
|
||||
};
|
||||
|
||||
export const configCommand = command(
|
||||
|
||||
39
src/commands/githook.ts
Normal file → Executable file
39
src/commands/githook.ts
Normal file → Executable file
@@ -1,18 +1,33 @@
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { command } from 'cleye';
|
||||
import { assertGitRepo } from '../utils/git.js';
|
||||
import { assertGitRepo, getCoreHooksPath } from '../utils/git.js';
|
||||
import { existsSync } from 'fs';
|
||||
import chalk from 'chalk';
|
||||
import { intro, outro } from '@clack/prompts';
|
||||
import { COMMANDS } from '../CommandsEnum.js';
|
||||
|
||||
const HOOK_NAME = 'prepare-commit-msg';
|
||||
const SYMLINK_URL = `.git/hooks/${HOOK_NAME}`;
|
||||
const DEFAULT_SYMLINK_URL = path.join('.git', 'hooks', HOOK_NAME);
|
||||
|
||||
export const isHookCalled = process.argv[1].endsWith(`/${SYMLINK_URL}`);
|
||||
const getHooksPath = async (): Promise<string> => {
|
||||
try {
|
||||
const hooksPath = await getCoreHooksPath();
|
||||
return path.join(hooksPath, HOOK_NAME);
|
||||
} catch (error) {
|
||||
return DEFAULT_SYMLINK_URL;
|
||||
}
|
||||
};
|
||||
|
||||
const isHookExists = existsSync(SYMLINK_URL);
|
||||
export const isHookCalled = async (): Promise<boolean> => {
|
||||
const hooksPath = await getHooksPath();
|
||||
return process.argv[1].endsWith(hooksPath);
|
||||
};
|
||||
|
||||
const isHookExists = async (): Promise<boolean> => {
|
||||
const hooksPath = await getHooksPath();
|
||||
return existsSync(hooksPath);
|
||||
};
|
||||
|
||||
export const hookCommand = command(
|
||||
{
|
||||
@@ -21,16 +36,16 @@ export const hookCommand = command(
|
||||
},
|
||||
async (argv) => {
|
||||
const HOOK_URL = __filename;
|
||||
|
||||
const SYMLINK_URL = await getHooksPath();
|
||||
try {
|
||||
await assertGitRepo();
|
||||
|
||||
const { setUnset: mode } = argv._;
|
||||
|
||||
if (mode === 'set') {
|
||||
intro(`setting opencommit as '${HOOK_NAME}' hook`);
|
||||
intro(`setting opencommit as '${HOOK_NAME}' hook at ${SYMLINK_URL}`);
|
||||
|
||||
if (isHookExists) {
|
||||
if (await isHookExists()) {
|
||||
let realPath;
|
||||
try {
|
||||
realPath = await fs.realpath(SYMLINK_URL);
|
||||
@@ -40,7 +55,7 @@ export const hookCommand = command(
|
||||
}
|
||||
|
||||
if (realPath === HOOK_URL)
|
||||
return outro(`opencommit is already set as '${HOOK_NAME}'`);
|
||||
return outro(`OpenCommit is already set as '${HOOK_NAME}'`);
|
||||
|
||||
throw new Error(
|
||||
`Different ${HOOK_NAME} is already set. Remove it before setting opencommit as '${HOOK_NAME}' hook.`
|
||||
@@ -55,9 +70,11 @@ export const hookCommand = command(
|
||||
}
|
||||
|
||||
if (mode === 'unset') {
|
||||
intro(`unsetting OpenCommit as '${HOOK_NAME}' hook`);
|
||||
intro(
|
||||
`unsetting opencommit as '${HOOK_NAME}' hook from ${SYMLINK_URL}`
|
||||
);
|
||||
|
||||
if (!isHookExists) {
|
||||
if (!(await isHookExists())) {
|
||||
return outro(
|
||||
`OpenCommit wasn't previously set as '${HOOK_NAME}' hook, nothing to remove`
|
||||
);
|
||||
@@ -75,7 +92,7 @@ export const hookCommand = command(
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`unsupported mode: ${mode}. Supported modes are: 'set' or 'unset'`
|
||||
`Unsupported mode: ${mode}. Supported modes are: 'set' or 'unset'`
|
||||
);
|
||||
} catch (error) {
|
||||
outro(`${chalk.red('✖')} ${error}`);
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import fs from 'fs/promises';
|
||||
import chalk from 'chalk';
|
||||
import { intro, outro } from '@clack/prompts';
|
||||
import { intro, outro, spinner } from '@clack/prompts';
|
||||
import { getChangedFiles, getDiff, getStagedFiles, gitAdd } from '../utils/git';
|
||||
import { getConfig } from './config';
|
||||
import { generateCommitMessageWithChatCompletion } from '../generateCommitMessageFromGitDiff';
|
||||
|
||||
const [messageFilePath, commitSource] = process.argv.slice(2);
|
||||
|
||||
export const prepareCommitMessageHook = async () => {
|
||||
export const prepareCommitMessageHook = async (
|
||||
isStageAllFlag: Boolean = false
|
||||
) => {
|
||||
try {
|
||||
if (!messageFilePath) {
|
||||
throw new Error(
|
||||
@@ -17,11 +19,14 @@ export const prepareCommitMessageHook = async () => {
|
||||
|
||||
if (commitSource) return;
|
||||
|
||||
const changedFiles = await getChangedFiles();
|
||||
if (changedFiles) await gitAdd({ files: changedFiles });
|
||||
else {
|
||||
outro("No changes detected, write some code and run `oc` again");
|
||||
if (isStageAllFlag) {
|
||||
const changedFiles = await getChangedFiles();
|
||||
|
||||
if (changedFiles) await gitAdd({ files: changedFiles });
|
||||
else {
|
||||
outro('No changes detected, write some code and run `oc` again');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
const staged = await getStagedFiles();
|
||||
@@ -38,11 +43,15 @@ export const prepareCommitMessageHook = async () => {
|
||||
);
|
||||
}
|
||||
|
||||
const spin = spinner();
|
||||
spin.start('Generating commit message');
|
||||
const commitMessage = await generateCommitMessageWithChatCompletion(
|
||||
await getDiff({ files: staged })
|
||||
);
|
||||
|
||||
if (typeof commitMessage !== 'string') throw new Error(commitMessage.error);
|
||||
if (typeof commitMessage !== 'string') {
|
||||
spin.stop('Error');
|
||||
throw new Error(commitMessage.error);
|
||||
} else spin.stop('Done');
|
||||
|
||||
const fileContent = await fs.readFile(messageFilePath);
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@ import {
|
||||
} from 'openai';
|
||||
import { api } from './api';
|
||||
import { getConfig } from './commands/config';
|
||||
import { mergeStrings } from './utils/mergeStrings';
|
||||
import { mergeDiffs } from './utils/mergeDiffs';
|
||||
import { i18n, I18nLocals } from './i18n';
|
||||
import { tokenCount } from './utils/tokenCount';
|
||||
|
||||
const config = getConfig();
|
||||
const translation = i18n[(config?.language as I18nLocals) || 'en'];
|
||||
@@ -13,40 +14,38 @@ const translation = i18n[(config?.language as I18nLocals) || 'en'];
|
||||
const INIT_MESSAGES_PROMPT: Array<ChatCompletionRequestMessage> = [
|
||||
{
|
||||
role: ChatCompletionRequestMessageRoleEnum.System,
|
||||
content: `You are to act as the author of a commit message in git. Your mission is to create clean and comprehensive commit messages in the conventional commit convention. I'll send you an output of 'git diff --staged' command, and you convert it into a commit message. ${
|
||||
config?.emoji
|
||||
? 'Use Gitmoji convention to preface the commit'
|
||||
: 'Do not preface the commit with anything'
|
||||
}, use the present tense. ${
|
||||
config?.description
|
||||
? 'Add a short description of what commit is about after the commit message. Don\'t start it with "This commit", just describe the changes.'
|
||||
: "Don't add any descriptions to the commit, only commit message."
|
||||
} Use ${translation.localLanguage} to answer.`
|
||||
// prettier-ignore
|
||||
content: `You are to act as the author of a commit message in git. Your mission is to create clean and comprehensive commit messages in the conventional commit convention and explain WHAT were the changes and WHY the changes were done. I'll send you an output of 'git diff --staged' command, and you convert it into a commit message.
|
||||
${config?.emoji? 'Use GitMoji convention to preface the commit.': 'Do not preface the commit with anything.'}
|
||||
${config?.description ? 'Add a short description of WHY the changes are done after the commit message. Don\'t start it with "This commit", just describe the changes.': "Don't add any descriptions to the commit, only commit message."}
|
||||
Use the present tense. Lines must not be longer than 74 characters. Use ${translation.localLanguage} to answer.`
|
||||
},
|
||||
{
|
||||
role: ChatCompletionRequestMessageRoleEnum.User,
|
||||
content: `diff --git a/src/server.ts b/src/server.ts
|
||||
index ad4db42..f3b18a9 100644
|
||||
--- a/src/server.ts
|
||||
+++ b/src/server.ts
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
initWinstonLogger();
|
||||
|
||||
const app = express();
|
||||
-const port = 7799;
|
||||
+const PORT = 7799;
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
@@ -34,6 +34,6 @@ app.use((_, res, next) => {
|
||||
// ROUTES
|
||||
app.use(PROTECTED_ROUTER_URL, protectedRouter);
|
||||
|
||||
-app.listen(port, () => {
|
||||
- console.log(\`Server listening on port \${port}\`);
|
||||
+app.listen(process.env.PORT || PORT, () => {
|
||||
+ console.log(\`Server listening on port \${PORT}\`);
|
||||
});`
|
||||
index ad4db42..f3b18a9 100644
|
||||
--- a/src/server.ts
|
||||
+++ b/src/server.ts
|
||||
@@ -10,7 +10,7 @@
|
||||
import {
|
||||
initWinstonLogger();
|
||||
|
||||
const app = express();
|
||||
-const port = 7799;
|
||||
+const PORT = 7799;
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
@@ -34,6 +34,6 @@
|
||||
app.use((_, res, next) => {
|
||||
// ROUTES
|
||||
app.use(PROTECTED_ROUTER_URL, protectedRouter);
|
||||
|
||||
-app.listen(port, () => {
|
||||
- console.log(\`Server listening on port \${port}\`);
|
||||
+app.listen(process.env.PORT || PORT, () => {
|
||||
+ console.log(\`Server listening on port \${PORT}\`);
|
||||
});`
|
||||
},
|
||||
{
|
||||
role: ChatCompletionRequestMessageRoleEnum.Assistant,
|
||||
@@ -80,8 +79,8 @@ interface GenerateCommitMessageError {
|
||||
}
|
||||
|
||||
const INIT_MESSAGES_PROMPT_LENGTH = INIT_MESSAGES_PROMPT.map(
|
||||
(msg) => msg.content
|
||||
).join('').length;
|
||||
(msg) => tokenCount(msg.content) + 4
|
||||
).reduce((a, b) => a + b, 0);
|
||||
|
||||
const MAX_REQ_TOKENS = 3900 - INIT_MESSAGES_PROMPT_LENGTH;
|
||||
|
||||
@@ -89,8 +88,11 @@ export const generateCommitMessageWithChatCompletion = async (
|
||||
diff: string
|
||||
): Promise<string | GenerateCommitMessageError> => {
|
||||
try {
|
||||
if (diff.length >= MAX_REQ_TOKENS) {
|
||||
const commitMessagePromises = getCommitMsgsPromisesFromFileDiffs(diff);
|
||||
if (tokenCount(diff) >= MAX_REQ_TOKENS) {
|
||||
const commitMessagePromises = getCommitMsgsPromisesFromFileDiffs(
|
||||
diff,
|
||||
MAX_REQ_TOKENS
|
||||
);
|
||||
|
||||
const commitMessages = await Promise.all(commitMessagePromises);
|
||||
|
||||
@@ -110,22 +112,28 @@ export const generateCommitMessageWithChatCompletion = async (
|
||||
}
|
||||
};
|
||||
|
||||
function getMessagesPromisesByLines(fileDiff: string, separator: string) {
|
||||
const lineSeparator = '\n@@';
|
||||
const [fileHeader, ...fileDiffByLines] = fileDiff.split(lineSeparator);
|
||||
function getMessagesPromisesByChangesInFile(
|
||||
fileDiff: string,
|
||||
separator: string,
|
||||
maxChangeLength: number
|
||||
) {
|
||||
const hunkHeaderSeparator = '@@ ';
|
||||
const [fileHeader, ...fileDiffByLines] = fileDiff.split(hunkHeaderSeparator);
|
||||
|
||||
// merge multiple line-diffs into 1 to save tokens
|
||||
const mergedLines = mergeStrings(
|
||||
fileDiffByLines.map((line) => lineSeparator + line),
|
||||
MAX_REQ_TOKENS
|
||||
const mergedChanges = mergeDiffs(
|
||||
fileDiffByLines.map((line) => hunkHeaderSeparator + line),
|
||||
maxChangeLength
|
||||
);
|
||||
|
||||
const lineDiffsWithHeader = mergedLines.map(
|
||||
(d) => fileHeader + lineSeparator + d
|
||||
const lineDiffsWithHeader = mergedChanges.map(
|
||||
(change) => fileHeader + change
|
||||
);
|
||||
|
||||
const commitMsgsFromFileLineDiffs = lineDiffsWithHeader.map((d) => {
|
||||
const messages = generateCommitMessageChatCompletionPrompt(separator + d);
|
||||
const commitMsgsFromFileLineDiffs = lineDiffsWithHeader.map((lineDiff) => {
|
||||
const messages = generateCommitMessageChatCompletionPrompt(
|
||||
separator + lineDiff
|
||||
);
|
||||
|
||||
return api.generateCommitMessage(messages);
|
||||
});
|
||||
@@ -133,20 +141,27 @@ function getMessagesPromisesByLines(fileDiff: string, separator: string) {
|
||||
return commitMsgsFromFileLineDiffs;
|
||||
}
|
||||
|
||||
function getCommitMsgsPromisesFromFileDiffs(diff: string) {
|
||||
export function getCommitMsgsPromisesFromFileDiffs(
|
||||
diff: string,
|
||||
maxDiffLength: number
|
||||
) {
|
||||
const separator = 'diff --git ';
|
||||
|
||||
const diffByFiles = diff.split(separator).slice(1);
|
||||
|
||||
// merge multiple files-diffs into 1 prompt to save tokens
|
||||
const mergedFilesDiffs = mergeStrings(diffByFiles, MAX_REQ_TOKENS);
|
||||
const mergedFilesDiffs = mergeDiffs(diffByFiles, maxDiffLength);
|
||||
|
||||
const commitMessagePromises = [];
|
||||
|
||||
for (const fileDiff of mergedFilesDiffs) {
|
||||
if (fileDiff.length >= MAX_REQ_TOKENS) {
|
||||
if (tokenCount(fileDiff) >= maxDiffLength) {
|
||||
// if file-diff is bigger than gpt context — split fileDiff into lineDiff
|
||||
const messagesPromises = getMessagesPromisesByLines(fileDiff, separator);
|
||||
const messagesPromises = getMessagesPromisesByChangesInFile(
|
||||
fileDiff,
|
||||
separator,
|
||||
maxDiffLength
|
||||
);
|
||||
|
||||
commitMessagePromises.push(...messagesPromises);
|
||||
} else {
|
||||
|
||||
6
src/i18n/cs.json
Normal file
6
src/i18n/cs.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"localLanguage": "česky",
|
||||
"commitFix": "fix(server.ts): zlepšení velikosti proměnné port na velká písmena PORT",
|
||||
"commitFeat": "feat(server.ts): přidání podpory pro proměnnou prostředí process.env.PORT",
|
||||
"commitDescription": "Proměnná port se nyní jmenuje PORT, což odpovídá konvenci pojmenování, protože PORT je konstanta. Podpora proměnné prostředí process.env.PORT umožňuje snadnější správu nastavení při spuštění."
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"localLanguage": "english",
|
||||
"commitFix": "fix(server.ts): change port variable case from lowercase port to uppercase PORT",
|
||||
"commitFeat": "feat(server.ts): add support for process.env.PORT environment variable",
|
||||
"commitFix": "fix(server.ts): change port variable case from lowercase port to uppercase PORT to improve semantics",
|
||||
"commitFeat": "feat(server.ts): add support for process.env.PORT environment variable to be able to run app on a configurable port",
|
||||
"commitDescription": "The port variable is now named PORT, which improves consistency with the naming conventions as PORT is a constant. Support for an environment variable allows the application to be more flexible as it can now run on any available port specified via the process.env.PORT environment variable."
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"localLanguage": "spanish",
|
||||
"commitFix": "fix(server.ts): cambiar la variable port de minúsculas a mayúsculas PORT",
|
||||
"commitFeat": "feat(server.ts): añadir soporte para la variable de entorno process.env.PORT",
|
||||
"commitDescription": "La variable port ahora se llama PORT, lo que mejora la coherencia con las convenciones de nomenclatura, ya que PORT es una constante. El soporte para una variable de entorno permite que la aplicación sea más flexible, ya que ahora puede ejecutarse en cualquier puerto disponible especificado a través de la variable de entorno process.env.PORT."
|
||||
}
|
||||
|
||||
{
|
||||
"localLanguage": "spanish",
|
||||
"commitFix": "fix(server.ts): cambiar la variable port de minúsculas a mayúsculas PORT",
|
||||
"commitFeat": "feat(server.ts): añadir soporte para la variable de entorno process.env.PORT",
|
||||
"commitDescription": "La variable port ahora se llama PORT, lo que mejora la coherencia con las convenciones de nomenclatura, ya que PORT es una constante. El soporte para una variable de entorno permite que la aplicación sea más flexible, ya que ahora puede ejecutarse en cualquier puerto disponible especificado a través de la variable de entorno process.env.PORT."
|
||||
}
|
||||
|
||||
6
src/i18n/id_ID.json
Normal file
6
src/i18n/id_ID.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"localLanguage": "bahasa",
|
||||
"commitFix": "fix(server.ts): mengubah huruf port variable dari huruf kecil ke huruf besar PORT",
|
||||
"commitFeat": "feat(server.ts): menambahkan support di process.env.PORT environment variabel",
|
||||
"commitDescription": "Port variabel bernama PORT, yang membantu konsistensi dengan memberi nama yaitu PORT yang konstan. Bantuan environment variabel membantu aplikasi lebih fleksibel, dan dapat di jalankan di port manapun yang tertulis pada process.env.PORT"
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import en from '../i18n/en.json' assert { type: 'json' };
|
||||
import cs from '../i18n/cs.json' assert { type: 'json' };
|
||||
import de from '../i18n/de.json' assert { type: 'json' };
|
||||
import fr from '../i18n/fr.json' assert { type: 'json' };
|
||||
import it from '../i18n/it.json' assert { type: 'json' };
|
||||
@@ -9,32 +10,55 @@ import ja from '../i18n/ja.json' assert { type: 'json' };
|
||||
import pt_br from '../i18n/pt_br.json' assert { type: 'json' };
|
||||
import vi_VN from '../i18n/vi_VN.json' assert { type: 'json' };
|
||||
import es_ES from '../i18n/es_ES.json' assert { type: 'json' };
|
||||
import sv from '../i18n/sv.json' assert { type: 'json' };
|
||||
import nl from '../i18n/nl.json' assert { type: 'json' };
|
||||
import ru from '../i18n/ru.json' assert { type: 'json' };
|
||||
import id_ID from '../i18n/id_ID.json' assert { type: 'json' };
|
||||
import pl from '../i18n/pl.json' assert { type: 'json' };
|
||||
import tr from '../i18n/tr.json' assert { type: 'json' };
|
||||
import th from '../i18n/th.json' assert { type: 'json' };
|
||||
|
||||
export enum I18nLocals {
|
||||
'en' = 'en',
|
||||
'zh_CN' = 'zh_CN',
|
||||
'zh_TW' = 'zh_TW',
|
||||
'ja' = 'ja',
|
||||
'cs' = 'cs',
|
||||
'de' = 'de',
|
||||
'fr' = 'fr',
|
||||
'nl' = 'nl',
|
||||
'it' = 'it',
|
||||
'ko' = 'ko',
|
||||
'pt_br' = 'pt_br',
|
||||
'es_ES' = 'es_ES'
|
||||
};
|
||||
'es_ES' = 'es_ES',
|
||||
'sv' = 'sv',
|
||||
'ru' = 'ru',
|
||||
'id_ID' = 'id_ID',
|
||||
'pl' = 'pl',
|
||||
'tr' = 'tr',
|
||||
'th' = 'th',
|
||||
}
|
||||
|
||||
export const i18n = {
|
||||
en,
|
||||
zh_CN,
|
||||
zh_TW,
|
||||
ja,
|
||||
cs,
|
||||
de,
|
||||
fr,
|
||||
it,
|
||||
ko,
|
||||
pt_br,
|
||||
vi_VN,
|
||||
es_ES
|
||||
es_ES,
|
||||
sv,
|
||||
id_ID,
|
||||
nl,
|
||||
ru,
|
||||
pl,
|
||||
tr,
|
||||
th
|
||||
};
|
||||
|
||||
export const I18N_CONFIG_ALIAS: { [key: string]: string[] } = {
|
||||
@@ -42,13 +66,21 @@ export const I18N_CONFIG_ALIAS: { [key: string]: string[] } = {
|
||||
zh_TW: ['zh_TW', '繁體中文', '繁體'],
|
||||
ja: ['ja', 'Japanese', 'にほんご'],
|
||||
ko: ['ko', 'Korean', '한국어'],
|
||||
de: ['de', 'German' ,'Deutsch'],
|
||||
cs: ['cs', 'Czech', 'česky'],
|
||||
de: ['de', 'German', 'Deutsch'],
|
||||
fr: ['fr', 'French', 'française'],
|
||||
it: ['it', 'Italian', 'italiano'],
|
||||
nl: ['nl', 'Dutch', 'Nederlands'],
|
||||
pt_br: ['pt_br', 'Portuguese', 'português'],
|
||||
vi_VN: ['vi_VN', 'Vietnamese', 'tiếng Việt'],
|
||||
en: ['en', 'English', 'english'],
|
||||
es_ES: ['es_ES', 'Spanish', 'español'],
|
||||
sv: ['sv', 'Swedish', 'Svenska'],
|
||||
ru: ['ru', 'Russian', 'русский'],
|
||||
id_ID: ['id_ID', 'Bahasa', 'bahasa'],
|
||||
pl: ['pl', 'Polish', 'Polski'],
|
||||
tr: ['tr', 'Turkish', 'Turkish'],
|
||||
th: ['th', 'Thai', 'ไทย']
|
||||
};
|
||||
|
||||
export function getI18nLocal(value: string): string | boolean {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"localLanguage": "italiano",
|
||||
"commitFix": "fix(server.ts): cambia il caso della variabile di porta da minuscolo port a maiuscolo PORT",
|
||||
"commitFeat": "funzionalità(server.ts): aggiungi supporto per la variabile di ambiente process.env.PORT",
|
||||
"commitDescription": "La variabile di porta è ora chiamata PORT, il che migliora la coerenza con le convenzioni di denominazione in quanto PORT è una costante. Il supporto per una variabile di ambiente consente all'applicazione di essere più flessibile poiché ora può essere eseguita su qualsiasi porta disponibile specificata tramite la variabile di ambiente process.env.PORT."
|
||||
"commitFix": "fix(server.ts): cambia la grafia della variabile della porta dal minuscolo port al maiuscolo PORT",
|
||||
"commitFeat": "feat(server.ts): aggiunge il supporto per la variabile di ambiente process.env.PORT",
|
||||
"commitDescription": "La variabile port è ora chiamata PORT, migliorando la coerenza con le convenzioni di denominazione in quanto PORT è una costante. Il supporto per una variabile di ambiente consente all'applicazione di essere più flessibile poiché ora può essere eseguita su qualsiasi porta disponibile specificata tramite la variabile di ambiente process.env.PORT."
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"localLanguage": "にほんご",
|
||||
"commitFix": "修正(server.ts): ポート変数のケースを小文字のポートから大文字のPORTに変更",
|
||||
"commitFeat": "新機能(server.ts): process.env.PORT環境変数のサポートを追加する",
|
||||
"commitDescription": "ポート変数は現在PORTという名前になっており、PORTは定数であるため命名規則に一貫性があります。環境変数のサポートにより、アプリケーションはより柔軟になり、process.env.PORT環境変数で指定された任意の利用可能なポートで実行できるようになりまし"
|
||||
"localLanguage": "日本語",
|
||||
"commitFix": "修正(server.ts): ポート変数を小文字のportから大文字のPORTに変更",
|
||||
"commitFeat": "新機能(server.ts): 環境変数process.env.PORTのサポートを追加",
|
||||
"commitDescription": "ポート変数は現在PORTという名前になり、定数であるPORTを使うことで命名規則に一貫性が生まれました。環境変数をサポートすることで、環境変数process.env.PORTで指定された任意の利用可能なポートで実行できるようになり、アプリケーションはより柔軟になりました。"
|
||||
}
|
||||
|
||||
6
src/i18n/nl.json
Normal file
6
src/i18n/nl.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"localLanguage": "Nederlands",
|
||||
"commitFix": "fix(server.ts): verander poortvariabele van kleine letters poort naar hoofdletters PORT",
|
||||
"commitFeat": "feat(server.ts): voeg ondersteuning toe voor process.env.PORT omgevingsvariabele",
|
||||
"commitDescription": "De poortvariabele heet nu PORT, wat de consistentie met de naamgevingsconventies verbetert omdat PORT een constante is. Ondersteuning voor een omgevingsvariabele maakt de applicatie flexibeler, omdat deze nu kan draaien op elke beschikbare poort die is gespecificeerd via de process.env.PORT omgevingsvariabele."
|
||||
}
|
||||
6
src/i18n/pl.json
Normal file
6
src/i18n/pl.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"localLanguage": "polski",
|
||||
"commitFix": "fix(server.ts): poprawa wielkości zmiennej port na pisane z dużymi literami PORT",
|
||||
"commitFeat": "feat(server.ts): dodanie obsługi zmiennej środowiskowej process.env.PORT",
|
||||
"commitDescription": "Zmienna port jest teraz nazwana PORT, co jest zgodne z konwencją nazewniczą ponieważ PORT jest stałą. Obsługa zmiennej środowiskowej process.env.PORT pozwala łatwiej zarządzać ustawieniami przy starcie."
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"localLanguage": "português",
|
||||
"commitFix": "fix(server.ts): altera o caso da variável de porta de port minúscula para PORT maiúscula",
|
||||
"commitFeat": "feat(server.ts): adiciona suporte para a variável de ambiente process.env.PORT",
|
||||
"commitDescription": "A variável de porta agora é denominada PORT, o que melhora a consistência com as convenções de nomenclatura, pois PORT é uma constante. O suporte para uma variável de ambiente permite que o aplicativo seja mais flexível, pois agora pode ser executado em qualquer porta disponível especificada por meio da variável de ambiente process.env.PORT."
|
||||
"localLanguage": "português",
|
||||
"commitFix": "fix(server.ts): altera o caso da variável de porta de port minúscula para PORT maiúscula",
|
||||
"commitFeat": "feat(server.ts): adiciona suporte para a variável de ambiente process.env.PORT",
|
||||
"commitDescription": "A variável de porta agora é denominada PORT, o que melhora a consistência com as convenções de nomenclatura, pois PORT é uma constante. O suporte para uma variável de ambiente permite que o aplicativo seja mais flexível, pois agora pode ser executado em qualquer porta disponível especificada por meio da variável de ambiente process.env.PORT."
|
||||
}
|
||||
|
||||
6
src/i18n/ru.json
Normal file
6
src/i18n/ru.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"localLanguage": "русский",
|
||||
"commitFix": "fix(server.ts): изменение регистра переменной порта с нижнего регистра port на верхний регистр PORT",
|
||||
"commitFeat": "feat(server.ts): добавлена поддержка переменной окружения process.env.PORT",
|
||||
"commitDescription": "Переменная port теперь называется PORT, что улучшает согласованность с соглашениями об именовании констант. Поддержка переменной окружения позволяет приложению быть более гибким, запускаясь на любом доступном порту, указанном с помощью переменной окружения process.env.PORT."
|
||||
}
|
||||
6
src/i18n/sv.json
Normal file
6
src/i18n/sv.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"localLanguage": "svenska",
|
||||
"commitFix": "fixa(server.ts): ändra variabelnamnet för port från små bokstäver till stora bokstäver PORT",
|
||||
"commitFeat": "nyhet(server.ts): lägg till stöd för process.env.PORT miljövariabel",
|
||||
"commitDescription": "Variabeln som innehåller portnumret heter nu PORT vilket förbättrar konsekvensen med namngivningskonventionerna eftersom PORT är en konstant. Stöd för en miljövariabel gör att applikationen kan vara mer flexibel då den nu kan köras på vilken port som helst som specificeras via miljövariabeln process.env.PORT."
|
||||
}
|
||||
6
src/i18n/th.json
Normal file
6
src/i18n/th.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"localLanguage": "ไทย",
|
||||
"commitFix": "fix(server.ts): เปลี่ยนตัวพิมพ์ของตัวแปร จากตัวพิมพ์เล็ก port เป็นตัวพิมพ์ใหญ่ PORT",
|
||||
"commitFeat": "feat(server.ts): เพิ่มการรองรับสำหรับตัวแปรสภาพแวดล้อม process.env.PORT",
|
||||
"commitDescription": "ตอนนี้ตัวแปรพอร์ตมีชื่อว่า PORT, ซึ่งปรับปรุงความสอดคล้องกับหลักการตั้งชื่อเนื่องจาก PORT เป็นค่าคงที่. การสนับสนุนสำหรับตัวแปรสภาพแวดล้อม ช่วยให้แอปพลิเคชันมีความยืดหยุ่นมากขึ้นเนื่องจาก สามารถทำงานบนพอร์ตใด ๆ ตามที่กำหนด ซึ่งระบุผ่านตัวแปรสภาพแวดล้อม process.env.PORT"
|
||||
}
|
||||
6
src/i18n/tr.json
Normal file
6
src/i18n/tr.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"localLanguage": "Turkish",
|
||||
"commitFix": "fix(server.ts): port değişkeni küçük harfli porttan büyük harfli PORT'a değiştirildi",
|
||||
"commitFeat": "feat(server.ts): process.env.PORT ortam değişkeni için destek eklendi.",
|
||||
"commitDescription": "Bağlantı noktası değişkeni artık PORT olarak adlandırıldı ve PORT bir sabit değişken olduğu için bu adlandırma tutarlılığı artırır. Ortam değişkeni desteği, artık process.env.PORT ortam değişkeni aracılığıyla belirtilen herhangi bir kullanılabilir bağlantı noktasında çalışabileceğinden uygulamanın daha esnek olmasını sağlar."
|
||||
}
|
||||
@@ -25,17 +25,25 @@ export const getOpenCommitIgnore = (): Ignore => {
|
||||
return ig;
|
||||
};
|
||||
|
||||
export const getCoreHooksPath = async(): Promise<string> => {
|
||||
const { stdout } = await execa('git', [
|
||||
'config',
|
||||
'core.hooksPath']);
|
||||
|
||||
return stdout;
|
||||
}
|
||||
|
||||
export const getStagedFiles = async (): Promise<string[]> => {
|
||||
const { stdout: gitDir } = await execa("git", [
|
||||
"rev-parse",
|
||||
"--show-toplevel"
|
||||
const { stdout: gitDir } = await execa('git', [
|
||||
'rev-parse',
|
||||
'--show-toplevel'
|
||||
]);
|
||||
|
||||
const { stdout: files } = await execa("git", [
|
||||
"diff",
|
||||
"--name-only",
|
||||
"--cached",
|
||||
"--relative",
|
||||
const { stdout: files } = await execa('git', [
|
||||
'diff',
|
||||
'--name-only',
|
||||
'--cached',
|
||||
'--relative',
|
||||
gitDir
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
export function mergeStrings(arr: string[], maxStringLength: number): string[] {
|
||||
import { tokenCount } from './tokenCount';
|
||||
export function mergeDiffs(arr: string[], maxStringLength: number): string[] {
|
||||
const mergedArr: string[] = [];
|
||||
let currentItem: string = arr[0];
|
||||
for (const item of arr.slice(1)) {
|
||||
if (currentItem.length + item.length <= maxStringLength) {
|
||||
if (tokenCount(currentItem + item) <= maxStringLength) {
|
||||
currentItem += item;
|
||||
} else {
|
||||
mergedArr.push(currentItem);
|
||||
13
src/utils/tokenCount.ts
Normal file
13
src/utils/tokenCount.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Tiktoken } from '@dqbd/tiktoken/lite';
|
||||
import cl100k_base from '@dqbd/tiktoken/encoders/cl100k_base.json' assert { type: 'json' };
|
||||
|
||||
export function tokenCount(content: string): number {
|
||||
const encoding = new Tiktoken(
|
||||
cl100k_base.bpe_ranks,
|
||||
cl100k_base.special_tokens,
|
||||
cl100k_base.pat_str
|
||||
);
|
||||
const tokens = encoding.encode(content);
|
||||
encoding.free();
|
||||
return tokens.length;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"target": "ESNext",
|
||||
"lib": ["ES5", "ES6"],
|
||||
|
||||
"module": "ESNext",
|
||||
|
||||
Reference in New Issue
Block a user