Compare commits

...

75 Commits

Author SHA1 Message Date
di-sukharev
5d0c69e849 1.1.11 2023-03-16 11:48:42 +08:00
di-sukharev
9754442efa chore(README.md): update Twitter handle in header 2023-03-16 11:48:31 +08:00
di-sukharev
a619cd1f78 docs(README.md): update payment information to include GPT-4 cost comparison 2023-03-15 17:35:25 +08:00
di-sukharev
1fc4a6b6c0 1.1.10 2023-03-15 17:33:55 +08:00
di-sukharev
798bddba81 docs(README.md): remove outdated information about minimum supported version of Node.js 2023-03-15 17:33:43 +08:00
di-sukharev
42ed2a31f4 fix(commit.ts): remove '-u' and 'origin' arguments from git push command to push to the current branch 2023-03-15 14:51:26 +08:00
di-sukharev
571e1e9d8f chore(TODO.md): mark batch small files in one request as completed
refactor(TODO.md): rephrase optimize prompt TODO to suggest exploring cleaner alternatives to prompt
2023-03-15 14:49:38 +08:00
di-sukharev
bd8de7a8ea feat(commit.ts): add '-u origin HEAD' flag to 'git push' command to set upstream branch and push current branch to it 2023-03-15 14:46:15 +08:00
di-sukharev
913bcd379f 1.1.9 2023-03-14 18:51:06 +08:00
di-sukharev
25468f67ad 1.1.8 2023-03-14 18:50:57 +08:00
Benny Neugebauer
6766f62848 Replace type assertion with built-in error detection (#10)
* refactor(api.ts): use built-in axios error detection
2023-03-14 18:50:25 +08:00
di-sukharev
71c36db265 1.1.7 2023-03-13 16:44:36 +08:00
di-sukharev
ed66e403e7 1.1.6 2023-03-13 16:44:19 +08:00
di-sukharev
b89e50ebbf * fix(generateCommitMessageFromGitDiff.ts): fix formatting of commit message prompt
* feat(generateCommitMessageFromGitDiff.ts): add description to commit message prompt
2023-03-13 16:43:59 +08:00
di-sukharev
38ebe49daa 1.1.5 2023-03-11 18:04:04 +08:00
di-sukharev
6ccded1f23 1.1.4 2023-03-11 13:24:58 +08:00
di-sukharev
31357132e4 * chore(api.ts): add error handling for openAI api error
* chore(generateCommitMessageFromGitDiff.ts): remove console.log statement
2023-03-11 13:24:02 +08:00
di-sukharev
b35a393152 * docs(README.md): add reminder to add payment details to OpenAI API key
* docs(api.ts): update error message to remind user to add payment details to OpenAI API key
* refactor(cli.ts): remove unused import
* refactor(config.ts): update error message to use outro instead of throwing an error and exit the process

* chore(generateCommitMessageFromGitDiff.ts): add console.log for error debugging
2023-03-11 13:23:46 +08:00
di-sukharev
8fe382a072 1.1.3 2023-03-11 01:02:37 +08:00
di-sukharev
4b703c634a * chore(TODO.md): update TODO list, remove completed task
* refactor(cli.ts): remove unnecessary async/await keywords, remove version check and "new version available" message
2023-03-11 01:01:26 +08:00
di-sukharev
6821e937cf 1.1.2 2023-03-11 00:58:18 +08:00
di-sukharev
69f3c48b2c * chore(TODO.md): mark "show new version available message" as completed
* chore(package.json): add `--tag latest` flag to `npm publish` command in `deploy` script
* refactor(cli.ts): add async/await to `prepareCommitMessageHook` and `commit` functions, and check for new version of `opencommit` after commit is made
2023-03-11 00:57:48 +08:00
di-sukharev
f49f1a86df * chore(package.json): update version from 1.0.17 to 1.1.1 2023-03-11 00:55:36 +08:00
di-sukharev
98945df561 1.0.17 2023-03-11 00:53:29 +08:00
di-sukharev
e8e190ff3d 1.0.16 2023-03-11 00:49:50 +08:00
di-sukharev
9c3f28b7c6 * chore(TODO.md): move TODO.md to .github/TODO.md
* chore(TODO.md): set prepare-commit-msg hook
* chore(cli.ts): remove async/await from commit and prepareCommitMessageHook calls
* feat(cli.ts): add check for new version available after commit
2023-03-11 00:49:22 +08:00
di-sukharev
e146d4d60d * fix(cli.ts): add curly braces to if statement in cli function to improve readability 2023-03-11 00:32:37 +08:00
di-sukharev
2ae35749a5 1.0.15 2023-03-11 00:28:58 +08:00
di-sukharev
8836c57fa4 * chore(commit.ts): add TODO comment to show proper error messages 2023-03-11 00:24:52 +08:00
di-sukharev
4b523e5782 1.0.14 2023-03-11 00:23:55 +08:00
di-sukharev
33491486bb * feat(CommandsEnum.ts): add COMMANDS enum
* refactor(api.ts): use CONFIG_MODES enum from config.ts
* refactor(config.ts): use COMMANDS and CONFIG_MODES enums, extract validateConfig function
* feat(config.ts): add CONFIG_MODES enum and refactor configCommand function to use it

* refactor(githook.ts): import COMMANDS enum from CommandsEnum.js file
2023-03-11 00:23:30 +08:00
di-sukharev
e76db8276b 1.0.13 2023-03-11 00:20:09 +08:00
di-sukharev
c2ae98170c * refactor(api.ts): move apiKey initialization to the top of the file
* feat(api.ts): add check for process arguments to avoid intro message if 'config set' command is used
2023-03-11 00:19:29 +08:00
di-sukharev
91987030f0 1.0.12 2023-03-11 00:15:34 +08:00
di-sukharev
2a55b08b51 * refactor(api.ts): remove redundant code block and process.exit(1) call 2023-03-11 00:15:17 +08:00
di-sukharev
ed4d6e0109 1.0.11 2023-03-10 22:49:43 +08:00
di-sukharev
6712e798c5 * feat(cli.ts): add check for new opencommit version after commit is made
* chore(cli.ts): import execa and outro from their respective packages
2023-03-10 22:49:27 +08:00
di-sukharev
1347962a93 1.0.10 2023-03-10 22:42:33 +08:00
di-sukharev
3ca9b9752f * fix(api.ts): add process.exit(1) to terminate the process if apiKey is not provided 2023-03-10 22:41:53 +08:00
di-sukharev
50e2f67a9b 1.0.9 2023-03-10 17:56:21 +08:00
di-sukharev
c1a4c3daf2 * chore: update package description and keywords
* chore: update README with new package description and title
2023-03-10 17:55:51 +08:00
di-sukharev
e4de6d8186 * feat(README.md): add OpenCommit example image to README
* chore(README.md): update OPENAI_API_KEY config key to use 'your_api_key' instead of 'your token'
* chore(README.md): update description of where the api key is stored
2023-03-10 15:59:57 +08:00
di-sukharev
5abe5d715d * refactor(commit.ts): remove unnecessary blank lines
* feat(commit.ts): add spinner to show progress of `git push` command
* feat(commit.ts): show success message after successful `git push` command execution
2023-03-10 15:24:49 +08:00
di-sukharev
32c34abd22 1.0.8 2023-03-09 21:32:24 +08:00
di-sukharev
1050cad95d * refactor(commit.ts): extract stdout from git push command into a variable 2023-03-09 21:32:07 +08:00
di-sukharev
7bbc97980e * refactor(commit.ts): remove unused stdout variable and simplify pushSpinner.stop() call 2023-03-09 21:31:31 +08:00
di-sukharev
2a9a3d5818 * chore(README.md): add emoji to the project description 2023-03-09 21:30:44 +08:00
di-sukharev
22935f38ba 1.0.7 2023-03-09 21:29:52 +08:00
di-sukharev
4ae6361ad8 * chore(package.json): update description with emojis. 2023-03-09 21:29:28 +08:00
di-sukharev
5a0a384cbe 1.0.6 2023-03-09 21:25:49 +08:00
di-sukharev
a8839353f7 * chore(commit.ts): add spinner to indicate git push process
* refactor(commit.ts): change success message to include spinner in `git push` process
2023-03-09 21:25:38 +08:00
di-sukharev
88006b8693 * fix(commit.ts): add check for cancelation of git push confirmation prompt 2023-03-09 21:23:58 +08:00
di-sukharev
5d9d1c972a 1.0.5 2023-03-09 21:22:46 +08:00
di-sukharev
3892bd0e69 * feat(commit.ts): add option to push commits after successful commit 2023-03-09 21:22:35 +08:00
di-sukharev
2b6cc5c360 * chore(README.md): update example section to clarify that all commits in the repo are done with OpenCommit 2023-03-09 21:20:17 +08:00
di-sukharev
c4c2600cf6 1.0.4 2023-03-09 15:29:34 +08:00
di-sukharev
c361aaa914 * refactor(generateCommitMessageFromGitDiff.ts): merge multiple line-diffs and multiple files-diffs to save tokens
* refactor(generateCommitMessageFromGitDiff.ts): split file-diff into line-diffs only if file-diff is bigger than gpt context
2023-03-09 15:28:18 +08:00
di-sukharev
f3d673185e deleted log txt file 2023-03-09 15:04:51 +08:00
di-sukharev
5615bdce86 * refactor(commit.ts): add stdout to commit function output
* fix(commit.ts): fix commit confirmation message to show correct status
2023-03-09 14:02:04 +08:00
di-sukharev
68b327bee7 * refactor(prepare-commit-msg-hook.ts): remove outro function call and its message from try block 2023-03-09 14:00:50 +08:00
di-sukharev
b747d70e69 1.0.3 2023-03-09 13:59:55 +08:00
di-sukharev
caa64fbcf9 * refactor(prepare-commit-msg-hook.ts): change appendFile to writeFile to write commit message to file
* chore(prepare-commit-msg-hook.ts): add newline character before appending file content to commit message
2023-03-09 13:58:27 +08:00
di-sukharev
1a49c08409 * chore(commit.ts): change stagedFilesSpinner message when no files are staged 2023-03-09 13:56:03 +08:00
di-sukharev
3399d65a0c 1.0.2 2023-03-07 23:02:22 +08:00
di-sukharev
d561170519 * refactor(api.ts): remove console.log statement
* fix(generateCommitMessageFromGitDiff.ts): increase MAX_REQ_TOKENS to 3900 to avoid exceeding OpenAI's limit
2023-03-07 22:37:13 +08:00
di-sukharev
bf29c260ca * 🚀 feat(generateCommitMessageFromGitDiff.ts): add mergeStrings utility function
* 🐛 fix(generateCommitMessageFromGitDiff.ts): remove unnecessary separator variable

* 🐛 fix: split file diffs by files
*  feat: add support for generating commit messages by file diffs

*  feat(generateCommitMessageFromGitDiff.ts): add mergeStrings utility function to merge string arrays
* 🐛 fix(generateCommitMessageFromGitDiff.ts): reduce MAX_REQ_TOKENS to 1000
*  feat(generateCommitMessageFromGitDiff.ts): add support for generating commit messages for large diffs by splitting them into smaller chunks and generating commit messages for each chunk using OpenAI's GPT-3 model.

* ♻️ refactor: extract getCommitMsgsPromisesFromFileDiffs function from generateCommitMessage function
* ♻️ refactor: extract getMessagesPromisesByLines function from getCommitMsgsPromisesFromFileDiffs function
*  feat: add support for merging file diffs into one commit message if it exceeds MAX_REQ_TOKENS limit

*  feat(mergeStrings.ts): add mergeStrings function to merge strings in an array based on maxStringLength
2023-03-07 16:19:00 +08:00
di-sukharev
9e2a3d8988 getMessagesPromisesByLines 2023-03-07 16:16:12 +08:00
di-sukharev
1ea5fbc430 * 🐛 fix(api.ts): return message content instead of whole response object
* 🚀 chore(generateCommitMessageFromGitDiff.ts): filter out null promises and update TODO comment
* 🚀 chore(tsconfig.json): update target to ES2020 and remove ES5 from lib
2023-03-07 15:51:10 +08:00
di-sukharev
55e9adf73d * 🐛 fix(cli.ts): add assert statement to packageJSON import
The assert statement was added to ensure that the imported packageJSON is of type JSON. This prevents any potential runtime errors that may occur if the imported file is not of the expected type.

* 🐛 fix(generateCommitMessageFromGitDiff.ts): adjust MAX_REQ_TOKENS to account for INIT_MESSAGES_PROMPT_LENGTH
* 💄 style(generateCommitMessageFromGitDiff.ts): remove unnecessary separator variable
The MAX_REQ_TOKENS constant was not accounting for the length of the INIT_MESSAGES_PROMPT, which caused the function to fail when the diff length was close to the limit. This has been fixed by adjusting the constant to include the prompt length. The separator variable was not being used and has been removed for clarity.

* 🚀 chore(tsconfig.json): update compiler options
The target compiler option has been updated to ESNext to allow for the use of the latest ECMAScript features. The lib compiler option has been updated to include ES6 in addition to ES5. The module compiler option has been updated to ESNext to allow for the use of the latest module syntax.
2023-03-07 15:21:16 +08:00
di-sukharev
60325f53b9 * 🚧 chore(prepare-commit-msg-hook.ts): remove console.log and add TODO comment
The console.log statement is removed as it is not needed. A TODO comment is added to remind the developer to change the code to read file and write file with commitMessage.
2023-03-06 23:56:38 +08:00
di-sukharev
3966c4c53a * 🐛 fix(prepare-commit-msg-hook.ts): remove console.log statement
The console.log statement was left in the code and is not needed. This commit removes it.
2023-03-06 23:52:34 +08:00
di-sukharev
2527c80f2f * 📝 docs(README.md): replace opencommit with oc in commands
The commands in the README.md file have been updated to use the new 'oc' command instead of the old 'opencommit' command. This improves consistency with the naming conventions and makes it easier to use the tool.
2023-03-06 23:41:47 +08:00
di-sukharev
e89fc96732 * 🎨 style(githook.ts): remove unused import
The import of fileURLToPath from the url module is not used in the file, so it has been removed to improve code readability and maintainability.
2023-03-06 23:35:39 +08:00
di-sukharev
b5d1057fd6 * 📝 docs(README.md): update link to commits
The link to the commits was updated to point to a specific commit (eae7618d57) instead of the general commits page. This provides a more direct and specific reference to the commits.
2023-03-06 23:22:00 +08:00
di-sukharev
5f310970cc * 📝 docs(README.md): remove emoji from header
Removed the cowboy emoji from the header of the README.md file to improve readability.

* 📝 chore(TODO.md): reorder TODO list
Reordered the TODO list in the TODO.md file to prioritize the task of making the bundle smaller by properly configuring esbuild.
2023-03-06 23:19:17 +08:00
16 changed files with 644 additions and 219 deletions

10
.github/TODO.md vendored Normal file
View File

@@ -0,0 +1,10 @@
# TODOs
- [x] set prepare-commit-msg hook
- [] show "new version available" message, look into this commit e146d4d cli.ts file
- [] make bundle smaller by properly configuring esbuild
- [] [build for both mjs and cjs](https://snyk.io/blog/best-practices-create-modern-npm-package/)
- [] do // TODOs in the code
- [x] batch small files in one request
- [] add tests
- [] optimize prompt, maybe no prompt would be cleaner

BIN
.github/opencommit-example.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

View File

@@ -2,38 +2,39 @@
<div>
<img src=".github/logo-grad.svg" alt="OpenCommit logo"/>
<h1 align="center">OpenCommit</h1>
<h4 align="center">Author <a href="https://github.com/di-sukharev">@di-sukharev</a> <a href="https://twitter.com/io_Y_oi"><img src="https://img.shields.io/twitter/follow/io_Y_oi?style=flat&label=io_Y_oi&logo=twitter&color=0bf&logoColor=fff" align="center"></a>
<h4 align="center">Follow the bird <a href="https://twitter.com/io_Y_oi"><img src="https://img.shields.io/twitter/follow/io_Y_oi?style=flat&label=io_Y_oi&logo=twitter&color=0bf&logoColor=fff" align="center"></a>
</h4>
</div>
<p>AI generates conventional commits with mind-blowing accuracy</p>
<h2>GPT CLI to auto-generate impressive commits in 1 second</h2>
<p>Killing lame commits with AI 🤯🔫</p>
<a href="https://www.npmjs.com/package/opencommit"><img src="https://img.shields.io/npm/v/opencommit" alt="Current version"></a>
</div>
---
## Examples
<div align="center">
<img src=".github/opencommit-example.png" alt="OpenCommit example"/>
</div>
Look into [the commits](https://github.com/di-sukharev/opencommit/commit) to see how OpenCommit works. Emoji and long commit description text is configurable.
All the commits in this repo are done with OpenCommit — look into [the commits](https://github.com/di-sukharev/opencommit/commit/eae7618d575ee8d2e9fff5de56da79d40c4bc5fc) to see how OpenCommit works. Emoji and long commit description text is configurable.
## Setup
> The minimum supported version of Node.js is the latest v14. Check your Node.js version with `node --version`.
1. Install opencommit globally to use in any repository:
```sh
npm install -g opencommit
```
2. Get your API key from [OpenAI](https://platform.openai.com/account/api-keys)
2. Get your API key from [OpenAI](https://platform.openai.com/account/api-keys). Make sure you add payment details, so API works.
3. Set the key to opencommit config:
```sh
opencommit config set OPENAI_API_KEY=<your token>
opencommit config set OPENAI_API_KEY=<your_api_key>
```
Your token isn't sent to anyone, it's saved in `~/.opencommit` config file.
Your api key is stored locally in `~/.opencommit` config file.
## Usage
@@ -60,27 +61,27 @@ oc
To add emoji:
```sh
opencommit config set emoji=true
oc config set emoji=true
```
To remove emoji:
```sh
opencommit config set emoji=false
oc config set emoji=false
```
### Postface commits with descriptions of changes 🤠
### Postface commits with descriptions of changes
To add descriptions:
```sh
opencommit config set description=true
oc config set description=true
```
To remove description:
```sh
opencommit config set description=false
oc config set description=false
```
## Git hook
@@ -90,24 +91,24 @@ You can set opencommit as Git [`prepare-commit-msg`](https://git-scm.com/docs/gi
To set the hook:
```sh
opencommit hook set
oc hook set
```
To unset the hook:
```sh
opencommit hook unset
oc hook unset
```
To use the hook:
```sh
git add <files...>
git commit
git add <files...>
git commit
```
Or follow the process of your IDE Source Control feature, when it calls `git commit` command — OpenCommit will integrate into the flow.
## Payments
You pay for your own requests to OpenAI API. OpenCommit uses ChatGPT official model, that is ~10x times cheaper than GPT-3.
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.

View File

@@ -1,8 +0,0 @@
# TODOs
- [] [build for both mjs and cjs](https://snyk.io/blog/best-practices-create-modern-npm-package/)
- [] make bundle smaller by properly configuring esbuild
- [] do // TODOs in the code
- [] batch small files in one request
- [] add tests
- [] make hook work

578
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "open-commit",
"version": "1.0.1",
"name": "opencommit",
"version": "1.1.11",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "open-commit",
"version": "1.0.1",
"name": "opencommit",
"version": "1.1.11",
"license": "ISC",
"dependencies": {
"@clack/prompts": "^0.6.1",
@@ -19,8 +19,8 @@
"openai": "^3.2.1"
},
"bin": {
"oc": "out/cli.mjs",
"opencommit": "out/cli.mjs"
"oc": "out/cli.cjs",
"opencommit": "out/cli.cjs"
},
"devDependencies": {
"@types/ini": "^1.3.31",
@@ -36,23 +36,23 @@
}
},
"node_modules/@clack/core": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@clack/core/-/core-0.3.0.tgz",
"integrity": "sha512-ujw1888RciTArxUvwLOf24XSygRX7F4qiCPI7WLH3zCTZJuqKPMcTS7Wqjz0x/AuMpwGPlzhKln4+sCuQqYxzA==",
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@clack/core/-/core-0.3.2.tgz",
"integrity": "sha512-FZnsNynwGDIDktx6PEZK1EuCkFpY4ldEX6VYvfl0dqeoLPb9Jpw1xoUXaVcGR8ExmYNm1w2vdGdJkEUYD/2pqg==",
"dependencies": {
"picocolors": "^1.0.0",
"sisteransi": "^1.0.5"
}
},
"node_modules/@clack/prompts": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.6.1.tgz",
"integrity": "sha512-7KuMST/5zB7KpvfR00kcnbOaXmfN6tkJmkLpAyV2Iv2SJ7oxFbhNFvR5OQJynSKDhU8oOp/eFMK6Q0k/DXsq8A==",
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.6.3.tgz",
"integrity": "sha512-AM+kFmAHawpUQv2q9+mcB6jLKxXGjgu/r2EQjEwujgpCdzrST6BJqYw00GRn56/L/Izw5U7ImoLmy00X/r80Pw==",
"bundleDependencies": [
"is-unicode-supported"
],
"dependencies": {
"@clack/core": "^0.3.0",
"@clack/core": "^0.3.2",
"is-unicode-supported": "*",
"picocolors": "^1.0.0",
"sisteransi": "^1.0.5"
@@ -81,6 +81,38 @@
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
"integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz",
"integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==",
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@eslint/eslintrc": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.0.tgz",
@@ -274,14 +306,14 @@
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.54.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.0.tgz",
"integrity": "sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw==",
"version": "5.54.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.1.tgz",
"integrity": "sha512-a2RQAkosH3d3ZIV08s3DcL/mcGc2M/UC528VkPULFxR9VnVPT8pBu0IyBAJJmVsCmhVfwQX1v6q+QGnmSe1bew==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.54.0",
"@typescript-eslint/type-utils": "5.54.0",
"@typescript-eslint/utils": "5.54.0",
"@typescript-eslint/scope-manager": "5.54.1",
"@typescript-eslint/type-utils": "5.54.1",
"@typescript-eslint/utils": "5.54.1",
"debug": "^4.3.4",
"grapheme-splitter": "^1.0.4",
"ignore": "^5.2.0",
@@ -308,14 +340,14 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "5.54.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.0.tgz",
"integrity": "sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ==",
"version": "5.54.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.1.tgz",
"integrity": "sha512-8zaIXJp/nG9Ff9vQNh7TI+C3nA6q6iIsGJ4B4L6MhZ7mHnTMR4YP5vp2xydmFXIy8rpyIVbNAG44871LMt6ujg==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.54.0",
"@typescript-eslint/types": "5.54.0",
"@typescript-eslint/typescript-estree": "5.54.0",
"@typescript-eslint/scope-manager": "5.54.1",
"@typescript-eslint/types": "5.54.1",
"@typescript-eslint/typescript-estree": "5.54.1",
"debug": "^4.3.4"
},
"engines": {
@@ -335,13 +367,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "5.54.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.0.tgz",
"integrity": "sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg==",
"version": "5.54.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.1.tgz",
"integrity": "sha512-zWKuGliXxvuxyM71UA/EcPxaviw39dB2504LqAmFDjmkpO8qNLHcmzlh6pbHs1h/7YQ9bnsO8CCcYCSA8sykUg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.54.0",
"@typescript-eslint/visitor-keys": "5.54.0"
"@typescript-eslint/types": "5.54.1",
"@typescript-eslint/visitor-keys": "5.54.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -352,13 +384,13 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "5.54.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.54.0.tgz",
"integrity": "sha512-WI+WMJ8+oS+LyflqsD4nlXMsVdzTMYTxl16myXPaCXnSgc7LWwMsjxQFZCK/rVmTZ3FN71Ct78ehO9bRC7erYQ==",
"version": "5.54.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.54.1.tgz",
"integrity": "sha512-WREHsTz0GqVYLIbzIZYbmUUr95DKEKIXZNH57W3s+4bVnuF1TKe2jH8ZNH8rO1CeMY3U4j4UQeqPNkHMiGem3g==",
"dev": true,
"dependencies": {
"@typescript-eslint/typescript-estree": "5.54.0",
"@typescript-eslint/utils": "5.54.0",
"@typescript-eslint/typescript-estree": "5.54.1",
"@typescript-eslint/utils": "5.54.1",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
},
@@ -379,9 +411,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "5.54.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.0.tgz",
"integrity": "sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ==",
"version": "5.54.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.1.tgz",
"integrity": "sha512-G9+1vVazrfAfbtmCapJX8jRo2E4MDXxgm/IMOF4oGh3kq7XuK3JRkOg6y2Qu1VsTRmWETyTkWt1wxy7X7/yLkw==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -392,13 +424,13 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.54.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.0.tgz",
"integrity": "sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ==",
"version": "5.54.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.1.tgz",
"integrity": "sha512-bjK5t+S6ffHnVwA0qRPTZrxKSaFYocwFIkZx5k7pvWfsB1I57pO/0M0Skatzzw1sCkjJ83AfGTL0oFIFiDX3bg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.54.0",
"@typescript-eslint/visitor-keys": "5.54.0",
"@typescript-eslint/types": "5.54.1",
"@typescript-eslint/visitor-keys": "5.54.1",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@@ -419,16 +451,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "5.54.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.54.0.tgz",
"integrity": "sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw==",
"version": "5.54.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.54.1.tgz",
"integrity": "sha512-IY5dyQM8XD1zfDe5X8jegX6r2EVU5o/WJnLu/znLPWCBF7KNGC+adacXnt5jEYS9JixDcoccI6CvE4RCjHMzCQ==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.54.0",
"@typescript-eslint/types": "5.54.0",
"@typescript-eslint/typescript-estree": "5.54.0",
"@typescript-eslint/scope-manager": "5.54.1",
"@typescript-eslint/types": "5.54.1",
"@typescript-eslint/typescript-estree": "5.54.1",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
@@ -445,12 +477,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.54.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.0.tgz",
"integrity": "sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA==",
"version": "5.54.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.1.tgz",
"integrity": "sha512-q8iSoHTgwCfgcRJ2l2x+xCbu8nBlRAlsQ33k24Adj8eoVBE0f8dUeI+bAa8F84Mv05UGbAx57g2zrRsYIooqQg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.54.0",
"@typescript-eslint/types": "5.54.1",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@@ -542,15 +574,11 @@
}
},
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"engines": {
"node": ">=8"
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
@@ -935,6 +963,54 @@
"esbuild-windows-arm64": "0.15.18"
}
},
"node_modules/esbuild-android-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz",
"integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-android-arm64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz",
"integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-darwin-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz",
"integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-darwin-arm64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz",
@@ -951,6 +1027,262 @@
"node": ">=12"
}
},
"node_modules/esbuild-freebsd-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz",
"integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-freebsd-arm64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz",
"integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-32": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz",
"integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz",
"integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-arm": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz",
"integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-arm64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz",
"integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-mips64le": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz",
"integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-ppc64le": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz",
"integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-riscv64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz",
"integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-s390x": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz",
"integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-netbsd-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz",
"integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-openbsd-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz",
"integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-sunos-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz",
"integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-windows-32": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz",
"integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-windows-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz",
"integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-windows-arm64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz",
"integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -1069,6 +1401,21 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/eslint/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/eslint/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -1125,9 +1472,9 @@
}
},
"node_modules/esquery": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz",
"integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
"integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
"dev": true,
"dependencies": {
"estraverse": "^5.1.0"
@@ -1206,31 +1553,6 @@
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
"node_modules/execa/node_modules/mimic-fn": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/execa/node_modules/onetime": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
"integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
"dependencies": {
"mimic-fn": "^4.0.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/external-editor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
@@ -1890,11 +2212,14 @@
}
},
"node_modules/mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
"engines": {
"node": ">=6"
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/minimatch": {
@@ -1967,14 +2292,14 @@
}
},
"node_modules/onetime": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
"integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
"dependencies": {
"mimic-fn": "^2.1.0"
"mimic-fn": "^4.0.0"
},
"engines": {
"node": ">=6"
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -2207,9 +2532,9 @@
]
},
"node_modules/readable-stream": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz",
"integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==",
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -2255,6 +2580,28 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/restore-cursor/node_modules/mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"engines": {
"node": ">=6"
}
},
"node_modules/restore-cursor/node_modules/onetime": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
"dependencies": {
"mimic-fn": "^2.1.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -2319,11 +2666,6 @@
"tslib": "^2.1.0"
}
},
"node_modules/rxjs/node_modules/tslib": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -2583,10 +2925,9 @@
}
},
"node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
},
"node_modules/tsutils": {
"version": "3.21.0",
@@ -2603,6 +2944,12 @@
"typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
}
},
"node_modules/tsutils/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -2726,17 +3073,6 @@
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/wrap-ansi/node_modules/ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/wrap-ansi/node_modules/strip-ansi": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",

View File

@@ -1,13 +1,17 @@
{
"name": "opencommit",
"version": "1.0.1",
"description": "AI generates conventional commits with mind-blowing accuracy.",
"version": "1.1.11",
"description": "GPT CLI to auto-generate impressive commits in 1 second. Killing lame commits with AI 🤯🔫",
"keywords": [
"git",
"chatgpt",
"gpt",
"ai",
"openai",
"opencommit",
"aicommit",
"aicommits",
"gptcommit",
"commit"
],
"main": "cli.js",
@@ -37,7 +41,7 @@
"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",
"deploy": "npm run build && npm version patch && npm publish",
"deploy": "npm run build && npm version patch && npm publish --tag latest",
"lint": "eslint src --ext ts && tsc --noEmit"
},
"devDependencies": {

4
src/CommandsEnum.ts Normal file
View File

@@ -0,0 +1,4 @@
export enum COMMANDS {
config = 'config',
hook = 'hook'
}

View File

@@ -1,39 +1,33 @@
import { intro, outro } from '@clack/prompts';
import axios from 'axios';
import chalk from 'chalk';
import {
ChatCompletionRequestMessage,
ChatCompletionResponseMessage,
Configuration as OpenAiApiConfiguration,
OpenAIApi
} from 'openai';
import { getConfig } from './commands/config';
import { CONFIG_MODES, getConfig } from './commands/config';
const config = getConfig();
let apiKey = config?.OPENAI_API_KEY;
if (!apiKey) {
const [command, mode] = process.argv.slice(2);
if (!apiKey && command !== 'config' && mode !== CONFIG_MODES.set) {
intro('opencommit');
outro(
'OPENAI_API_KEY is not set, please run `oc config set OPENAI_API_KEY=<your token>`'
'OPENAI_API_KEY is not set, please run `oc config set OPENAI_API_KEY=<your token>. Make sure you add payment details, so API works.`'
);
outro(
'For help Look into README https://github.com/di-sukharev/opencommit#setup'
'For help look into README https://github.com/di-sukharev/opencommit#setup'
);
process.exit(1);
}
// if (!apiKey) {
// intro('opencommit');
// const apiKey = await text({
// message: 'input your OPENAI_API_KEY'
// });
// setConfig([[CONFIG_KEYS.OPENAI_API_KEY as string, apiKey as any]]);
// outro('OPENAI_API_KEY is set');
// }
class OpenAi {
private openAiApiConfiguration = new OpenAiApiConfiguration({
apiKey: apiKey
@@ -43,7 +37,7 @@ class OpenAi {
public generateCommitMessage = async (
messages: Array<ChatCompletionRequestMessage>
): Promise<ChatCompletionResponseMessage | undefined> => {
): Promise<string | undefined> => {
try {
const { data } = await this.openAI.createChatCompletion({
model: 'gpt-3.5-turbo',
@@ -55,10 +49,20 @@ class OpenAi {
const message = data.choices[0].message;
return message;
} catch (error) {
console.error('openAI api error', { error });
throw error;
return message?.content;
} catch (error: unknown) {
outro(`${chalk.red('✖')} ${error}`);
if (axios.isAxiosError<{ error?: { message: string } }>(error) && error.response?.status === 401) {
const openAiError = error.response.data.error;
if (openAiError?.message) outro(openAiError.message);
outro(
'For help look into README https://github.com/di-sukharev/opencommit#setup'
);
}
process.exit(1);
}
};
}

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env node
import { cli } from 'cleye';
import packageJSON from '../package.json';
import packageJSON from '../package.json' assert { type: 'json' };
import { configCommand } from './commands/config';
import { hookCommand, isHookCalled } from './commands/githook.js';

View File

@@ -16,6 +16,7 @@ const generateCommitMessageFromGitDiff = async (
commitSpinner.start('Generating the commit message');
const commitMessage = await generateCommitMessageWithChatCompletion(diff);
// TODO: show proper error messages
if (typeof commitMessage !== 'string') {
const errorMessages = {
[GenerateCommitMessageErrorEnum.emptyMessage]:
@@ -44,8 +45,22 @@ ${chalk.grey('——————————————————')}`
});
if (isCommitConfirmedByUser && !isCancel(isCommitConfirmedByUser)) {
await execa('git', ['commit', '-m', commitMessage]);
const { stdout } = await execa('git', ['commit', '-m', commitMessage]);
outro(`${chalk.green('✔')} successfully committed`);
outro(stdout);
const isPushConfirmedByUser = await confirm({
message: 'Do you want to run `git push`?'
});
if (isPushConfirmedByUser && !isCancel(isPushConfirmedByUser)) {
const pushSpinner = spinner();
pushSpinner.start('Running `git push`');
const { stdout } = await execa('git', ['push']);
pushSpinner.stop(`${chalk.green('✔')} successfully pushed all commits`);
if (stdout) outro(stdout);
}
} else outro(`${chalk.gray('✖')} process cancelled`);
};
@@ -79,7 +94,7 @@ export async function commit(isStageAllFlag = false) {
.bold('`oc`')} command.`
);
stagedFilesSpinner.stop('Counting staged files');
stagedFilesSpinner.stop('No files are staged');
const isStageAllAndCommitConfirmedByUser = await confirm({
message: 'Do you want to stage all files and generate commit message?'
});

View File

@@ -5,6 +5,7 @@ import { existsSync, writeFileSync, readFileSync } from 'fs';
import { homedir } from 'os';
import { intro, outro } from '@clack/prompts';
import chalk from 'chalk';
import { COMMANDS } from '../CommandsEnum';
export enum CONFIG_KEYS {
OPENAI_API_KEY = 'OPENAI_API_KEY',
@@ -12,13 +13,21 @@ export enum CONFIG_KEYS {
emoji = 'emoji'
}
export enum CONFIG_MODES {
get = 'get',
set = 'set'
}
const validateConfig = (
key: string,
condition: any,
validationMessage: string
) => {
if (!condition) {
throw new Error(`Unsupported config key ${key}: ${validationMessage}`);
outro(
`${chalk.red('✖')} Unsupported config key ${key}: ${validationMessage}`
);
process.exit(1);
}
};
@@ -110,7 +119,7 @@ export const setConfig = (keyValues: [key: string, value: string][]) => {
export const configCommand = command(
{
name: 'config',
name: COMMANDS.config,
parameters: ['<mode>', '<key=values...>']
},
async (argv) => {
@@ -118,12 +127,12 @@ export const configCommand = command(
try {
const { mode, keyValues } = argv._;
if (mode === 'get') {
if (mode === CONFIG_MODES.get) {
const config = getConfig() || {};
for (const key of keyValues) {
outro(`${key}=${config[key as keyof typeof config]}`);
}
} else if (mode === 'set') {
} else if (mode === CONFIG_MODES.set) {
await setConfig(
keyValues.map((keyValue) => keyValue.split('=') as [string, string])
);

View File

@@ -1,11 +1,11 @@
import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
import { command } from 'cleye';
import { assertGitRepo } 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}`;
@@ -16,7 +16,7 @@ const isHookExists = existsSync(SYMLINK_URL);
export const hookCommand = command(
{
name: 'hook',
name: COMMANDS.hook,
parameters: ['<set/unset>']
},
async (argv) => {

View File

@@ -37,9 +37,12 @@ export const prepareCommitMessageHook = async () => {
if (typeof commitMessage !== 'string') throw new Error(commitMessage.error);
await fs.appendFile(messageFilePath, commitMessage);
const fileContent = await fs.readFile(messageFilePath);
outro(`${chalk.green('✔')} commit done`);
await fs.writeFile(
messageFilePath,
commitMessage + '\n' + fileContent.toString()
);
} catch (error) {
outro(`${chalk.red('✖')} ${error}`);
process.exit(1);

View File

@@ -4,6 +4,7 @@ import {
} from 'openai';
import { api } from './api';
import { getConfig } from './commands/config';
import { mergeStrings } from './utils/mergeStrings';
const config = getConfig();
@@ -48,8 +49,8 @@ const INIT_MESSAGES_PROMPT: Array<ChatCompletionRequestMessage> = [
{
role: ChatCompletionRequestMessageRoleEnum.Assistant,
// prettier-ignore
content: `* ${config?.emoji ? '🐛 ' : ''}fix(server.ts): change port variable case from lowercase port to uppercase PORT
* ${config?.emoji ? '✨ ' : ''}feat(server.ts): add support for process.env.PORT environment variable
content: `${config?.emoji ? '🐛 ' : ''}fix(server.ts): change port variable case from lowercase port to uppercase PORT
${config?.emoji ? '✨ ' : ''}feat(server.ts): add support for process.env.PORT environment variable
${config?.description ? '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.' : ''}`
}
];
@@ -81,47 +82,79 @@ const INIT_MESSAGES_PROMPT_LENGTH = INIT_MESSAGES_PROMPT.map(
(msg) => msg.content
).join('').length;
const MAX_REQ_TOKENS = 3900 - INIT_MESSAGES_PROMPT_LENGTH;
export const generateCommitMessageWithChatCompletion = async (
diff: string
): Promise<string | GenerateCommitMessageError> => {
try {
const MAX_REQ_TOKENS = 3900;
if (diff.length >= MAX_REQ_TOKENS) {
const commitMessagePromises = getCommitMsgsPromisesFromFileDiffs(diff);
if (INIT_MESSAGES_PROMPT_LENGTH + diff.length >= MAX_REQ_TOKENS) {
const separator = 'diff --git ';
const diffByFiles = diff.split(separator).slice(1);
const commitMessages = [];
for (const diffFile of diffByFiles) {
if (INIT_MESSAGES_PROMPT_LENGTH + diffFile.length >= MAX_REQ_TOKENS)
continue;
const messages = generateCommitMessageChatCompletionPrompt(
separator + diffFile
);
const commitMessage = await api.generateCommitMessage(messages);
// TODO: handle this edge case
if (!commitMessage?.content) continue;
commitMessages.push(commitMessage?.content);
}
const commitMessages = await Promise.all(commitMessagePromises);
return commitMessages.join('\n\n');
} else {
const messages = generateCommitMessageChatCompletionPrompt(diff);
const commitMessage = await api.generateCommitMessage(messages);
if (!commitMessage)
return { error: GenerateCommitMessageErrorEnum.emptyMessage };
return commitMessage;
}
const messages = generateCommitMessageChatCompletionPrompt(diff);
const commitMessage = await api.generateCommitMessage(messages);
if (!commitMessage)
return { error: GenerateCommitMessageErrorEnum.emptyMessage };
return commitMessage.content;
} catch (error) {
return { error: GenerateCommitMessageErrorEnum.internalError };
}
};
function getMessagesPromisesByLines(fileDiff: string, separator: string) {
const lineSeparator = '\n@@';
const [fileHeader, ...fileDiffByLines] = fileDiff.split(lineSeparator);
// merge multiple line-diffs into 1 to save tokens
const mergedLines = mergeStrings(
fileDiffByLines.map((line) => lineSeparator + line),
MAX_REQ_TOKENS
);
const lineDiffsWithHeader = mergedLines.map(
(d) => fileHeader + lineSeparator + d
);
const commitMsgsFromFileLineDiffs = lineDiffsWithHeader.map((d) => {
const messages = generateCommitMessageChatCompletionPrompt(separator + d);
return api.generateCommitMessage(messages);
});
return commitMsgsFromFileLineDiffs;
}
function getCommitMsgsPromisesFromFileDiffs(diff: string) {
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 commitMessagePromises = [];
for (const fileDiff of mergedFilesDiffs) {
if (fileDiff.length >= MAX_REQ_TOKENS) {
// if file-diff is bigger than gpt context — split fileDiff into lineDiff
const messagesPromises = getMessagesPromisesByLines(fileDiff, separator);
commitMessagePromises.push(...messagesPromises);
} else {
const messages = generateCommitMessageChatCompletionPrompt(
separator + fileDiff
);
commitMessagePromises.push(api.generateCommitMessage(messages));
}
}
return commitMessagePromises;
}

14
src/utils/mergeStrings.ts Normal file
View File

@@ -0,0 +1,14 @@
export function mergeStrings(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) {
currentItem += item;
} else {
mergedArr.push(currentItem);
currentItem = item;
}
}
mergedArr.push(currentItem);
return mergedArr;
}

View File

@@ -1,9 +1,9 @@
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES5"],
"lib": ["ES5", "ES6"],
"module": "CommonJS",
"module": "ESNext",
// "rootDir": "./src",
"moduleResolution": "node",
"resolveJsonModule": true,