aicommit2 2.4.27 → 2.4.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +125 -348
  2. package/dist/cli.mjs +2 -2
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -21,6 +21,29 @@
21
21
 
22
22
  ______________________________________________________________________
23
23
 
24
+ ## Table of Contents
25
+
26
+ - [Quick start](#quick-start)
27
+ - [Introduction](#introduction)
28
+ - [Key features](#key-features)
29
+ - [Supported providers](#supported-providers)
30
+ - [Setup](#setup)
31
+ - [How it works](#how-it-works)
32
+ - [Version Control Systems](#version-control-systems)
33
+ - [Usage](#usage)
34
+ - [Integrations](#integrations)
35
+ - [LazyGit](#lazygit)
36
+ - [Git Hooks](#git-hooks)
37
+ - [Configuration](#configuration)
38
+ - [General Settings](#general-settings)
39
+ - [Logging](#logging)
40
+ - [Custom Prompt Template](#custom-prompt-template)
41
+ - [Watch Commit Mode](#watch-commit-mode)
42
+ - [Upgrading](#upgrading)
43
+ - [Contributing](#contributing)
44
+
45
+ ______________________________________________________________________
46
+
24
47
  ## Quick start
25
48
 
26
49
  ```bash
@@ -44,7 +67,7 @@ aicommit2
44
67
 
45
68
  ## Introduction
46
69
 
47
- AICommit2 automatically generates commit messages using AI. It supports [Git](https://git-scm.com/), [YADM](https://yadm.io/) (Yet Another Dotfiles Manager), and [Jujutsu](https://github.com/jj-vcs/jj)(jj) repositories with automatic detection. [AICommits](https://github.com/Nutlope/aicommits) inspired the core functionalities and architecture of this project.
70
+ _aicommit2_ automatically generates commit messages using AI. It supports [Git](https://git-scm.com/), [YADM](https://yadm.io/) (Yet Another Dotfiles Manager), and [Jujutsu](https://github.com/jj-vcs/jj) (jj) repositories with automatic detection. [AICommits](https://github.com/Nutlope/aicommits) inspired the core functionalities and architecture of this project.
48
71
 
49
72
  ## Key features
50
73
 
@@ -52,7 +75,7 @@ AICommit2 automatically generates commit messages using AI. It supports [Git](ht
52
75
  - **[Multi-AI Support](#cloud-ai-services)**: Integrates with OpenAI, Anthropic Claude, Google Gemini, Mistral AI, Cohere, Groq, Ollama and more
53
76
  - **[OpenAI API Compatibility](docs/providers/compatible.md)**: Support for any service that implements the OpenAI API specification
54
77
  - **[Reactive CLI](#usage)**: Enables simultaneous requests to multiple AIs and selection of the best commit message
55
- - **[Git Hook Integration](#git-hook)**: Can be used as a prepare-commit-msg hook
78
+ - **[Git Hook Integration](#git-hooks)**: Can be used as a prepare-commit-msg hook
56
79
  - **[Custom Prompt](#custom-prompt-template)**: Supports user-defined system prompt templates
57
80
 
58
81
  ## Supported providers
@@ -80,12 +103,12 @@ AICommit2 automatically generates commit messages using AI. It supports [Git](ht
80
103
  1. Install _aicommit2_:
81
104
 
82
105
  **Via Homebrew (recommended for macOS/Linux):**
83
- ```sh
106
+ ```bash
84
107
  brew install aicommit2
85
108
  ```
86
109
 
87
110
  **Via npm:**
88
- ```sh
111
+ ```bash
89
112
  npm install -g aicommit2
90
113
  ```
91
114
 
@@ -93,7 +116,7 @@ npm install -g aicommit2
93
116
 
94
117
  2. Set up API keys (**at least ONE key must be set**):
95
118
 
96
- ```sh
119
+ ```bash
97
120
  aicommit2 config set OPENAI.key=<your key>
98
121
  aicommit2 config set ANTHROPIC.key=<your key>
99
122
  # ... (similar commands for other providers)
@@ -101,7 +124,7 @@ aicommit2 config set ANTHROPIC.key=<your key>
101
124
 
102
125
  3. Run _aicommit2_ in your Git or Jujutsu repository:
103
126
 
104
- ```shell
127
+ ```bash
105
128
  # For Git repositories
106
129
  git add <files...>
107
130
  aicommit2
@@ -118,7 +141,7 @@ aicommit2
118
141
 
119
142
  If you use the Nix package manager, aicommit2 can be installed directly using the provided flake:
120
143
 
121
- ```sh
144
+ ```bash
122
145
  # Install temporarily in your current shell
123
146
  nix run github:tak-bro/aicommit2
124
147
 
@@ -157,7 +180,7 @@ Add aicommit2 to your flake inputs:
157
180
 
158
181
  To enter a development shell with all dependencies:
159
182
 
160
- ```sh
183
+ ```bash
161
184
  nix develop github:tak-bro/aicommit2
162
185
  ```
163
186
 
@@ -165,7 +188,7 @@ After setting up with Nix, you'll still need to configure API keys as described
165
188
 
166
189
  #### From Source
167
190
 
168
- ```sh
191
+ ```bash
169
192
  git clone https://github.com/tak-bro/aicommit2.git
170
193
  cd aicommit2
171
194
  npm run build
@@ -205,7 +228,7 @@ aicommit2
205
228
 
206
229
  ### YADM Support
207
230
 
208
- AICommit2 supports [YADM (Yet Another Dotfiles Manager)](https://yadm.io/) for managing dotfiles:
231
+ _aicommit2_ supports [YADM (Yet Another Dotfiles Manager)](https://yadm.io/) for managing dotfiles:
209
232
 
210
233
  ```bash
211
234
  # Standard YADM workflow
@@ -240,7 +263,7 @@ yadm clone <url>
240
263
 
241
264
  ### Jujutsu Support
242
265
 
243
- AICommit2 also supports [Jujutsu (jj)](https://github.com/martinvonz/jj) repositories:
266
+ _aicommit2_ also supports [Jujutsu (jj)](https://github.com/jj-vcs/jj) repositories:
244
267
 
245
268
  ```bash
246
269
  # Automatic jj detection (no staging needed)
@@ -261,7 +284,7 @@ aicommit2 config set forceGit=true
261
284
 
262
285
  **jj new Behavior:**
263
286
 
264
- By default, AICommit2 only runs `jj describe` to set the commit message, without creating a new changeset. This matches the workflow of many Jujutsu users who prefer to manually control when to run `jj new`.
287
+ By default, _aicommit2_ only runs `jj describe` to set the commit message, without creating a new changeset. This matches the workflow of many Jujutsu users who prefer to manually control when to run `jj new`.
265
288
 
266
289
  To automatically run `jj new` after describing (mimics `jj commit` behavior):
267
290
 
@@ -324,16 +347,16 @@ aicommit2 --jj
324
347
 
325
348
  You can call `aicommit2` directly to generate a commit message for your staged changes:
326
349
 
327
- ```sh
350
+ ```bash
328
351
  git add <files...>
329
352
  aicommit2
330
353
  ```
331
354
 
332
355
  `aicommit2` passes down unknown flags to `git commit`, so you can pass in [`commit` flags](https://git-scm.com/docs/git-commit).
333
356
 
334
- For example, you can stage all changes in tracked files with as you commit:
357
+ For example, you can stage all changes in tracked files as you commit:
335
358
 
336
- ```sh
359
+ ```bash
337
360
  aicommit2 --all # or -a
338
361
  ```
339
362
 
@@ -368,7 +391,7 @@ aicommit2 --all # or -a
368
391
  - Useful when working with custom commit conventions that require specific casing
369
392
  - `--hook-mode`: Run as a Git hook, typically used with [`prepare-commit-msg` hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#_committing_workflow_hooks) hook (default: **false**)
370
393
  - This mode is automatically enabled when running through the Git hook system
371
- - See [Git hook](#git-hook) section for more details
394
+ - See [Git Hooks](#git-hooks) section for more details
372
395
  - `--pre-commit`: Run in [pre-commit](https://pre-commit.com/) framework mode (default: **false**)
373
396
  - This option is specifically for use with the pre-commit framework
374
397
  - See [Integration with pre-commit framework](#integration-with-pre-commit-framework) section for setup instructions
@@ -379,12 +402,12 @@ aicommit2 --all # or -a
379
402
  - `--output` or `-o`: Output format for non-interactive mode (default: **none**)
380
403
  - Use `--output json` for JSON Lines format (one JSON object per line)
381
404
  - Outputs `{"subject":"...","body":"..."}` for each generated message
382
- - Designed for integration with tools like [LazyGit](#lazygit-integration)
405
+ - Designed for integration with tools like [LazyGit](#lazygit)
383
406
  - Skips TUI and exits after outputting messages
384
407
 
385
408
  Examples:
386
409
 
387
- ```sh
410
+ ```bash
388
411
  # Generate multiple commit messages with clipboard and file exclusions
389
412
  aicommit2 --locale "jp" --all --type "conventional" --generate 3 --clipboard --exclude "*.json" --exclude "*.ts"
390
413
 
@@ -401,15 +424,17 @@ aicommit2 -d -c
401
424
  aicommit2 --verbose # or -v
402
425
  ```
403
426
 
404
- ### LazyGit Integration
427
+ ## Integrations
405
428
 
406
- AICommit2 supports non-interactive JSON output mode for seamless integration with [LazyGit](https://github.com/jesseduffield/lazygit).
429
+ ### LazyGit
430
+
431
+ _aicommit2_ supports non-interactive JSON output mode for seamless integration with [LazyGit](https://github.com/jesseduffield/lazygit).
407
432
 
408
433
  #### Setup
409
434
 
410
435
  Use the `--output json` flag to get AI-generated commit messages in JSON Lines format:
411
436
 
412
- ```sh
437
+ ```bash
413
438
  aicommit2 --output json
414
439
  # Output: {"subject":"feat: add user authentication","body":""}
415
440
  # Output: {"subject":"fix: resolve login bug","body":"Fixes issue with session handling"}
@@ -468,23 +493,23 @@ customCommands:
468
493
 
469
494
  > **Note:** The editable mode (`Shift+A`) currently supports editing the subject only. The AI-generated body is not carried over to the edit prompt.
470
495
 
471
- ### Git hook
496
+ ### Git Hooks
472
497
 
473
- You can also integrate _aicommit2_ with Git via the [`prepare-commit-msg`](https://git-scm.com/docs/githooks#_prepare_commit_msg) hook. This lets you use Git like you normally would, and edit the commit message before committing.
498
+ You can integrate _aicommit2_ with Git via the [`prepare-commit-msg`](https://git-scm.com/docs/githooks#_prepare_commit_msg) hook. This lets you use Git like you normally would, and edit the commit message before committing.
474
499
 
475
500
  #### Automatic Installation
476
501
 
477
502
  In the Git repository you want to install the hook in:
478
503
 
479
- ```sh
504
+ ```bash
480
505
  aicommit2 hook install
481
506
  ```
482
507
 
483
508
  #### Manual Installation
484
509
 
485
- if you prefer to set up the hook manually, create or edit the `.git/hooks/prepare-commit-msg` file:
510
+ If you prefer to set up the hook manually, create or edit the `.git/hooks/prepare-commit-msg` file:
486
511
 
487
- ```sh
512
+ ```bash
488
513
  #!/bin/sh
489
514
  # your-other-hook "$@"
490
515
  aicommit2 --hook-mode "$@"
@@ -492,13 +517,13 @@ aicommit2 --hook-mode "$@"
492
517
 
493
518
  Make the hook executable:
494
519
 
495
- ```sh
520
+ ```bash
496
521
  chmod +x .git/hooks/prepare-commit-msg
497
522
  ```
498
523
 
499
524
  ##### Use with a custom `core.hooksPath`
500
525
 
501
- If you are using [`husky`](https://typicode.github.io/husky/)** or have configured a custom [`core.hooksPath`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-corehooksPath), update the corresponding hooks file instead. For Husky users, this file is `.husky/prepare-commit-message`.
526
+ If you are using [`husky`](https://typicode.github.io/husky/) or have configured a custom [`core.hooksPath`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-corehooksPath), update the corresponding hooks file instead. For Husky users, this file is `.husky/prepare-commit-message`.
502
527
 
503
528
  #### Integration with pre-commit Framework
504
529
 
@@ -522,19 +547,19 @@ Make sure you have:
522
547
  2. Installed aicommit2 globally: `npm install -g aicommit2`
523
548
  3. Run `pre-commit install --hook-type prepare-commit-msg` to set up the hook
524
549
 
525
- > **Note** : The `--pre-commit` flag is specifically designed for use with the pre-commit framework and ensures proper integration with other pre-commit hooks.
550
+ > **Note:** The `--pre-commit` flag is specifically designed for use with the pre-commit framework and ensures proper integration with other pre-commit hooks.
526
551
 
527
552
  #### Uninstall
528
553
 
529
554
  In the Git repository you want to uninstall the hook from:
530
555
 
531
- ```sh
556
+ ```bash
532
557
  aicommit2 hook uninstall
533
558
  ```
534
559
 
535
560
  Or manually delete the `.git/hooks/prepare-commit-msg` file.
536
561
 
537
- ### Configuration
562
+ ## Configuration
538
563
 
539
564
  aicommit2 supports configuration via command-line arguments, environment variables, and a configuration file. Settings are resolved in the following order of precedence:
540
565
 
@@ -543,7 +568,7 @@ aicommit2 supports configuration via command-line arguments, environment variabl
543
568
  3. Configuration file
544
569
  4. Default values
545
570
 
546
- #### Configuration File Location
571
+ ### Configuration File Location
547
572
 
548
573
  aicommit2 follows the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/latest/index.html) for its configuration file. The configuration file is named `config.ini` and is in INI format. It is resolved in the following order of precedence:
549
574
 
@@ -555,11 +580,11 @@ The first existing file found in this order will be used. If no configuration fi
555
580
 
556
581
  You can find the path of the currently loaded configuration file using the `config path` command:
557
582
 
558
- ```sh
583
+ ```bash
559
584
  aicommit2 config path
560
585
  ```
561
586
 
562
- #### Environment Variable Expansion in Config File
587
+ ### Environment Variable Expansion in Config File
563
588
 
564
589
  You can use environment variables in your configuration file values. Both `$VAR` and `${VAR}` syntax are supported.
565
590
 
@@ -571,7 +596,7 @@ key=$OPENAI_API_KEY
571
596
  url=${CUSTOM_API_URL}/v1
572
597
  ```
573
598
 
574
- #### Reading and Setting Configuration
599
+ ### Reading and Setting Configuration
575
600
 
576
601
  - READ: `aicommit2 config get [<key> [<key> ...]]`
577
602
  - SET: `aicommit2 config set <key>=<value>`
@@ -579,7 +604,7 @@ url=${CUSTOM_API_URL}/v1
579
604
 
580
605
  Example:
581
606
 
582
- ```sh
607
+ ```bash
583
608
  # Get all configurations
584
609
  aicommit2 config get
585
610
 
@@ -596,7 +621,7 @@ aicommit2 config del GEMINI
596
621
  aicommit2 config del timeout
597
622
  ```
598
623
 
599
- #### Environment Variables
624
+ ### Environment Variables
600
625
 
601
626
  You can configure API keys using environment variables. This is particularly useful for CI/CD environments or when you don't want to store keys in the configuration file.
602
627
 
@@ -621,20 +646,20 @@ DEEPSEEK_API_KEY="your-deepseek-key"
621
646
 
622
647
  Usage Example:
623
648
 
624
- ```sh
649
+ ```bash
625
650
  OPENAI_API_KEY="your-openai-key" ANTHROPIC_API_KEY="your-anthropic-key" aicommit2
626
651
  ```
627
652
 
628
653
  > **Note**: Environment variables take precedence over configuration file settings.
629
654
 
630
- #### How to Configure in detail
655
+ ### How to Configure in detail
631
656
 
632
657
  _aicommit2_ offers flexible configuration options for all AI services, including support for specifying multiple models. You can configure settings via command-line arguments, environment variables, or a configuration file.
633
658
 
634
659
  1. **Command-line arguments**: Use the format `--[Model].[Key]=value`.
635
660
  To specify multiple models, use the `--[Model].model=model1,model2` format.
636
661
 
637
- ```sh
662
+ ```bash
638
663
  aicommit2 --OPENAI.locale="jp" --GEMINI.temperature="0.5" --OPENAI.model="gpt-4o-mini,gpt-3.5-turbo"
639
664
  ```
640
665
 
@@ -669,282 +694,61 @@ _aicommit2_ offers flexible configuration options for all AI services, including
669
694
 
670
695
  > The priority of settings is: **Command-line Arguments > Environment Variables > Model-Specific Settings > General Settings > Default Values**.
671
696
 
697
+ ### Configuration Examples
698
+
699
+ ```bash
700
+ aicommit2 config set \
701
+ generate=2 \
702
+ topP=0.8 \
703
+ maxTokens=1024 \
704
+ temperature=0.7 \
705
+ OPENAI.key="sk-..." OPENAI.model="gpt-4o-mini" OPENAI.temperature=0.5 \
706
+ ANTHROPIC.key="sk-..." ANTHROPIC.model="claude-3-5-haiku-20241022" ANTHROPIC.maxTokens=2000 \
707
+ MISTRAL.key="your-key" MISTRAL.model="mistral-small-latest" \
708
+ OLLAMA.model="llama3.2" OLLAMA.numCtx=4096 OLLAMA.watchMode=true
709
+ ```
710
+
711
+ > 🔍 **Detailed Support Info**: Check each provider's documentation for specific limits and behaviors:
712
+ >
713
+ > - [OpenAI](docs/providers/openai.md)
714
+ > - [Anthropic Claude](docs/providers/anthropic.md)
715
+ > - [Gemini](docs/providers/gemini.md)
716
+ > - [Mistral & Codestral](docs/providers/mistral.md)
717
+ > - [Cohere](docs/providers/cohere.md)
718
+ > - [Groq](docs/providers/groq.md)
719
+ > - [Perplexity](docs/providers/perplexity.md)
720
+ > - [DeepSeek](docs/providers/deepseek.md)
721
+ > - [GitHub Models](docs/providers/github-models.md)
722
+ > - [OpenAI API Compatibility](docs/providers/compatible.md)
723
+ > - [Ollama](docs/providers/ollama.md)
724
+
672
725
  ## General Settings
673
726
 
674
- The following settings can be applied to most models, but support may vary.
675
- Please check the documentation for each specific model to confirm which settings are supported.
727
+ For detailed information about all available settings, see the [General Settings documentation](docs/settings.md).
676
728
 
677
729
  | Setting | Description | Default |
678
730
  | ---------------------- | ------------------------------------------------------------------- | ------------ |
679
- | `envKey` | Custom environment variable name for the API key | - |
680
- | `systemPrompt` | System Prompt text | - |
681
- | `systemPromptPath` | Path to system prompt file | - |
682
- | `exclude` | Files to exclude from AI analysis | - |
683
- | `type` | Type of commit message to generate | conventional |
684
731
  | `locale` | Locale for the generated commit messages | en |
685
732
  | `generate` | Number of commit messages to generate | 1 |
686
- | `logging` | Enable logging | true |
687
- | `includeBody` | Whether the commit message includes body | false |
688
- | `maxLength` | Maximum character length of the Subject of generated commit message | 50 |
689
- | `disableLowerCase` | Disable automatic lowercase conversion of commit messages | false |
733
+ | `type` | Type of commit message (`conventional` / `gitmoji`) | conventional |
734
+ | `maxLength` | Maximum character length of the commit subject | 50 |
690
735
  | `timeout` | Request timeout (milliseconds) | 10000 |
691
736
  | `temperature` | Model's creativity (0.0 - 2.0) | 0.7 |
692
737
  | `maxTokens` | Maximum number of tokens to generate | 1024 |
693
- | `topP` | Nucleus sampling | 0.9 |
694
- | `codeReview` | Whether to include an automated code review in the process | false |
695
- | `codeReviewPromptPath` | Path to code review prompt file | - |
696
- | `disabled` | Whether a specific model is enabled or disabled | false |
697
-
698
- > 👉 **Tip:** To set the General Settings for each model, use the following command.
699
- >
700
- > ```shell
701
- > aicommit2 config set OPENAI.locale="jp"
702
- > aicommit2 config set CODESTRAL.type="gitmoji"
703
- > aicommit2 config set GEMINI.includeBody=true
704
- > ```
705
-
706
- ##### envKey
707
-
708
- - Allows users to specify a custom environment variable name for their API key.
709
- - If `envKey` is not explicitly set, the system defaults to using an environment variable named after the service, followed by `_API_KEY` (e.g., `OPENAI_API_KEY` for OpenAI, `GEMINI_API_KEY` for Gemini).
710
- - This setting provides flexibility for managing API keys, especially when multiple services are used or when specific naming conventions are required.
711
-
712
- ```sh
713
- aicommit2 config set OPENAI.envKey="MY_CUSTOM_OPENAI_KEY"
714
- ```
715
-
716
- > `envKey` is used to retrieve the API key from your system's environment variables. Ensure the specified environment variable is set with your API key.
717
-
718
- ##### systemPrompt
719
-
720
- - Allow users to specify a custom system prompt
721
-
722
- ```sh
723
- aicommit2 config set systemPrompt="Generate git commit message."
724
- ```
725
-
726
- > `systemPrompt` takes precedence over `systemPromptPath` and does not apply at the same time.
727
-
728
- ##### systemPromptPath
729
-
730
- - Allow users to specify a custom file path for their own system prompt template
731
- - Please see [Custom Prompt Template](#custom-prompt-template)
732
- - **Note**: Paths can be absolute or relative to the configuration file location.
733
-
734
- ```sh
735
- aicommit2 config set systemPromptPath="/path/to/user/prompt.txt"
736
- ```
737
-
738
- ##### exclude
739
-
740
- - Files to exclude from AI analysis
741
- - It is applied with the `--exclude` option of the CLI option. All files excluded through `--exclude` in CLI and `exclude` general setting.
742
-
743
- ```sh
744
- aicommit2 config set exclude="*.ts"
745
- aicommit2 config set exclude="*.ts,*.json"
746
- ```
747
-
748
- > NOTE: `exclude` option does not support per model. It is **only** supported by General Settings.
749
-
750
- ##### forceGit
751
-
752
- Default: `false`
753
-
754
- Force Git detection even in Jujutsu repositories (useful when you have both `.jj` and `.git` directories):
755
-
756
- ```sh
757
- aicommit2 config set forceGit=true
758
- ```
759
-
760
- This is equivalent to using the `FORCE_GIT=true` environment variable, but persistent across sessions.
761
-
762
- ##### type
763
-
764
- Default: `conventional`
765
-
766
- Supported: `conventional`, `gitmoji`
767
-
768
- The type of commit message to generate:
769
-
770
- **Conventional Commits**: Follow the [Conventional Commits](https://conventionalcommits.org/) specification:
771
-
772
- ```sh
773
- aicommit2 config set type="conventional"
774
- ```
775
-
776
- **Gitmoji**: Use [Gitmoji](https://gitmoji.dev/) emojis in commit messages:
777
-
778
- ```sh
779
- aicommit2 config set type="gitmoji"
780
- ```
781
-
782
- ##### locale
783
-
784
- Default: `en`
785
-
786
- The locale to use for the generated commit messages. Consult the list of codes in: https://wikipedia.org/wiki/List_of_ISO_639_language_codes.
787
-
788
- ```sh
789
- aicommit2 config set locale="jp"
790
- ```
791
-
792
- ##### generate
793
-
794
- Default: `1`
795
-
796
- The number of commit messages to generate to pick from.
797
-
798
- Note, this will use more tokens as it generates more results.
799
-
800
- ```sh
801
- aicommit2 config set generate=2
802
- ```
803
-
804
- ##### logging
805
-
806
- Default: `true`
807
-
808
- This boolean option controls whether the application generates log files. When enabled, both the general application logs and the AI request/response logs are written to their respective paths. For a detailed explanation of all logging settings, including how to enable/disable logging and manage log files, please refer to the main [Logging](#main-logging-section) section.
809
-
810
- - **Log File Example**:
811
- ![log-path](https://github.com/tak-bro/aicommit2/blob/main/img/log_path.png?raw=true)
812
-
813
- ##### includeBody
814
-
815
- Default: `false`
816
-
817
- This option determines whether the commit message includes body. If you want to include body in message, you can set it to `true`.
818
-
819
- ```sh
820
- aicommit2 config set includeBody="true"
821
- ```
822
-
823
- ![ignore_body_false](https://github.com/tak-bro/aicommit2/blob/main/img/demo_body_min.gif?raw=true)
824
-
825
- ```sh
826
- aicommit2 config set includeBody="false"
827
- ```
828
-
829
- ![ignore_body_true](https://github.com/tak-bro/aicommit2/blob/main/img/ignore_body_true.png?raw=true)
830
-
831
- ##### maxLength
832
-
833
- The maximum character length of the Subject of generated commit message
834
-
835
- Default: `50`
836
-
837
- ```sh
838
- aicommit2 config set maxLength=100
839
- ```
840
-
841
- ##### disableLowerCase
842
-
843
- Disable automatic lowercase conversion of commit messages
844
-
845
- Default: `false`
846
-
847
- By default, AICommit2 converts the first character of commit types and descriptions to lowercase to follow conventional commit standards. Set this to `true` to preserve the original casing.
848
-
849
- ```sh
850
- aicommit2 config set disableLowerCase=true
851
- ```
852
-
853
- You can also use the CLI flag:
854
-
855
- ```sh
856
- aicommit2 --disable-lowercase
857
- ```
858
-
859
- ##### timeout
860
-
861
- The timeout for network requests in milliseconds.
862
-
863
- Default: `10_000` (10 seconds)
864
-
865
- ```sh
866
- aicommit2 config set timeout=20000 # 20s
867
- ```
868
-
869
- > **Note**: Each AI provider has its own default timeout value, and if the configured timeout is less than the provider's default, the setting will be ignored.
870
-
871
- ##### temperature
872
-
873
- The temperature (0.0-2.0) is used to control the randomness of the output
874
-
875
- Default: `0.7`
876
-
877
- ```sh
878
- aicommit2 config set temperature=0.3
879
- ```
880
-
881
- ##### maxTokens
882
-
883
- The maximum number of tokens that the AI models can generate.
884
-
885
- Default: `1024`
886
-
887
- ```sh
888
- aicommit2 config set maxTokens=3000
889
- ```
890
-
891
- ##### topP
892
-
893
- Default: `0.9`
894
-
895
- Nucleus sampling, where the model considers the results of the tokens with top_p probability mass.
896
-
897
- > **Note**: Claude 4.x models do not support using `temperature` and `top_p` simultaneously. For these models, `top_p` is automatically excluded.
898
-
899
- ```sh
900
- aicommit2 config set topP=0.2
901
- ```
902
-
903
- ##### disabled
904
-
905
- Default: `false`
906
-
907
- This option determines whether a specific model is enabled or disabled. If you want to disable a particular model, you can set this option to `true`.
908
-
909
- To disable a model, use the following commands:
910
-
911
- ```sh
912
- aicommit2 config set GEMINI.disabled="true"
913
- aicommit2 config set GROQ.disabled="true"
914
- ```
915
-
916
- ##### codeReview
917
-
918
- Default: `false`
919
-
920
- The `codeReview` parameter determines whether to include an automated code review in the process.
738
+ | `includeBody` | Whether the commit message includes body | false |
739
+ | `codeReview` | Enable automated code review | false |
740
+ | `systemPromptPath` | Path to custom system prompt file | - |
921
741
 
922
- ```sh
923
- aicommit2 config set codeReview=true
742
+ ```bash
743
+ # Example: Set settings for a specific model
744
+ aicommit2 config set OPENAI.locale="jp"
745
+ aicommit2 config set GEMINI.temperature=0.5
746
+ aicommit2 config set ANTHROPIC.includeBody=true
924
747
  ```
925
748
 
926
- > NOTE: When enabled, aicommit2 will perform a code review before generating commit messages.
927
-
928
- <img src="https://github.com/tak-bro/aicommit2/blob/main/img/code_review.gif?raw=true" alt="CODE_REVIEW" />
929
-
930
- ⚠️ **CAUTION**
749
+ > 👉 For all settings and detailed explanations, see [docs/settings.md](docs/settings.md)
931
750
 
932
- - The `codeReview` feature is currently experimental.
933
- - This feature performs a code review before generating commit messages.
934
- - Using this feature will significantly increase the overall processing time.
935
- - It may significantly impact performance and cost.
936
- - **The code review process consumes a large number of tokens.**
937
-
938
- ##### codeReviewPromptPath
939
-
940
- - Allow users to specify a custom file path for code review
941
- - **Note**: Paths can be absolute or relative to the configuration file location.
942
-
943
- ```sh
944
- aicommit2 config set codeReviewPromptPath="/path/to/user/prompt.txt"
945
- ```
946
-
947
- ## Available General Settings by Model
751
+ ### Available Settings by Model
948
752
 
949
753
  | | timeout | temperature | maxTokens | topP |
950
754
  | :-----------------------: | :-----: | :---------: | :-------: | :--: |
@@ -961,39 +765,7 @@ aicommit2 config set codeReviewPromptPath="/path/to/user/prompt.txt"
961
765
  | **Ollama** | ✓ | ✓ | | ✓ |
962
766
  | **OpenAI API-Compatible** | ✓ | ✓ | ✓ | ✓ |
963
767
 
964
- > All AI support the following options in General Settings.
965
- >
966
- > - systemPrompt, systemPromptPath, codeReview, codeReviewPromptPath, exclude, type, locale, generate, logging, includeBody, maxLength, disableLowerCase
967
-
968
- ## Configuration Examples
969
-
970
- ```
971
- aicommit2 config set \
972
- generate=2 \
973
- topP=0.8 \
974
- maxTokens=1024 \
975
- temperature=0.7 \
976
- OPENAI.key="sk-..." OPENAI.model="gpt-4o-mini" OPENAI.temperature=0.5 \
977
- ANTHROPIC.key="sk-..." ANTHROPIC.model="claude-3-5-haiku-20241022" ANTHROPIC.maxTokens=2000 \
978
- MISTRAL.key="your-key" MISTRAL.model="mistral-small-latest" \
979
- OLLAMA.model="llama3.2" OLLAMA.numCtx=4096 OLLAMA.watchMode=true
980
- ```
981
-
982
- > 🔍 **Detailed Support Info**: Check each provider's documentation for specific limits and behaviors:
983
- >
984
- > - [OpenAI](docs/providers/openai.md)
985
- > - [Anthropic Claude](docs/providers/anthropic.md)
986
- > - [Gemini](docs/providers/gemini.md)
987
- > - [Mistral & Codestral](docs/providers/mistral.md)
988
- > - [Cohere](docs/providers/cohere.md)
989
- > - [Groq](docs/providers/groq.md)
990
- > - [Perplexity](docs/providers/perplexity.md)
991
- > - [DeepSeek](docs/providers/deepseek.md)
992
- > - [GitHub Models](docs/providers/github-models.md)
993
- > - [OpenAI API Compatibility](docs/providers/compatible.md)
994
- > - [Ollama](docs/providers/ollama.md)
995
-
996
- ## <a id="main-logging-section"></a>Logging
768
+ ## Logging
997
769
 
998
770
  The application utilizes two distinct logging systems to provide comprehensive insights into its operations:
999
771
 
@@ -1037,7 +809,7 @@ _aicommit2_ generates detailed logs for debugging and tracking AI requests. You
1037
809
 
1038
810
  #### View Log Files
1039
811
 
1040
- ```sh
812
+ ```bash
1041
813
  # List all log files with details
1042
814
  aicommit2 log list
1043
815
 
@@ -1047,14 +819,14 @@ aicommit2 log path
1047
819
 
1048
820
  #### Open Log Directory
1049
821
 
1050
- ```sh
822
+ ```bash
1051
823
  # Open logs directory in your file manager
1052
824
  aicommit2 log open
1053
825
  ```
1054
826
 
1055
827
  #### Clean Up Logs
1056
828
 
1057
- ```sh
829
+ ```bash
1058
830
  # Remove all log files
1059
831
  aicommit2 log removeAll
1060
832
  ```
@@ -1074,7 +846,7 @@ _aicommit2_ supports custom prompt templates through the `systemPromptPath` opti
1074
846
 
1075
847
  To use a custom prompt template, specify the path to your template file when running the tool:
1076
848
 
1077
- ```
849
+ ```bash
1078
850
  aicommit2 config set systemPromptPath="/path/to/user/prompt.txt"
1079
851
  aicommit2 config set OPENAI.systemPromptPath="/path/to/another-prompt.txt"
1080
852
  ```
@@ -1088,10 +860,10 @@ For the above command, OpenAI uses the prompt in the `another-prompt.txt` file,
1088
860
  Your custom template can include placeholders for various commit options.
1089
861
  Use curly braces `{}` to denote these placeholders for options. The following placeholders are supported:
1090
862
 
1091
- - [{locale}](#locale): The language for the commit message (**string**)
1092
- - [{maxLength}](#max-length): The maximum length for the commit message (**number**)
1093
- - [{type}](#type): The type of the commit message (**conventional** or **gitmoji**)
1094
- - [{generate}](#generate): The number of commit messages to generate (**number**)
863
+ - `{locale}`: The language for the commit message (default: **en**)
864
+ - `{maxLength}`: The maximum length for the commit message (default: **50**)
865
+ - `{type}`: The type of the commit message (**conventional** or **gitmoji**)
866
+ - `{generate}`: The number of commit messages to generate (default: **1**)
1095
867
 
1096
868
  #### Example Template
1097
869
 
@@ -1138,7 +910,7 @@ This ensures that the output is consistently formatted as a JSON array, regardle
1138
910
 
1139
911
  Watch Commit mode allows you to monitor Git commits in real-time and automatically perform AI code reviews using the `--watch-commit` flag.
1140
912
 
1141
- ```sh
913
+ ```bash
1142
914
  aicommit2 --watch-commit
1143
915
  ```
1144
916
 
@@ -1148,7 +920,7 @@ This feature only works within Git repository directories and automatically trig
1148
920
  2. Performs AI code review
1149
921
  3. Displays results in real-time
1150
922
 
1151
- > For detailed configuration of the code review feature, please refer to the [codeReview](#codereview) section. The settings in that section are shared with this feature.
923
+ > For detailed configuration of the code review feature, please refer to the [codeReview](docs/settings.md#codereview) section. The settings in that section are shared with this feature.
1152
924
 
1153
925
  ⚠️ **CAUTION**
1154
926
 
@@ -1158,7 +930,7 @@ This feature only works within Git repository directories and automatically trig
1158
930
  - It is recommended to **carefully monitor your token usage** when using this feature
1159
931
  - To use this feature, you must enable watch mode for at least one AI model:
1160
932
 
1161
- ```sh
933
+ ```bash
1162
934
  aicommit2 config set [MODEL].watchMode="true"
1163
935
  ```
1164
936
 
@@ -1166,13 +938,17 @@ aicommit2 config set [MODEL].watchMode="true"
1166
938
 
1167
939
  Check the installed version with:
1168
940
 
1169
- ```
941
+ ```bash
1170
942
  aicommit2 --version
1171
943
  ```
1172
944
 
1173
945
  If it's not the [latest version](https://github.com/tak-bro/aicommit2/releases/latest), run:
1174
946
 
1175
- ```sh
947
+ ```bash
948
+ # Via Homebrew
949
+ brew upgrade aicommit2
950
+
951
+ # Via npm
1176
952
  npm update -g aicommit2
1177
953
  ```
1178
954
 
@@ -1215,6 +991,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
1215
991
  </tr>
1216
992
  <tr>
1217
993
  <td align="center"><a href="https://github.com/jaytaylor"><img src="https://avatars.githubusercontent.com/jaytaylor" width="100px;" alt=""/><br /><sub><b>@jaytaylor</b></sub></a><br /><a href="https://github.com/tak-bro/aicommit2/commits?author=jaytaylor" title="Code">💻</a></td>
994
+ <td align="center"><a href="https://github.com/denniswebb"><img src="https://avatars.githubusercontent.com/denniswebb" width="100px;" alt=""/><br /><sub><b>@denniswebb</b></sub></a><br /><a href="https://github.com/tak-bro/aicommit2/commits?author=denniswebb" title="Code">💻</a></td>
1218
995
  </tr>
1219
996
  </table>
1220
997
  <!-- markdownlint-restore -->
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{command as de,cli as Mn}from"cleye";import{createRequire as Rn}from"module";import Dn from"crypto";import X from"fs";import Fe from"os";import x from"path";import{Buffer as Tr}from"node:buffer";import ge from"node:path";import Rt,{ChildProcess as jr,exec as On}from"node:child_process";import ae from"node:process";import Nn,{execSync as Ze,exec as Fn}from"child_process";import{fileURLToPath as Br}from"node:url";import _n,{constants as Gr}from"node:os";import Hr from"assert";import Ur from"events";import{createWriteStream as Ln,createReadStream as Tn,readFileSync as jn}from"node:fs";import Bn from"buffer";import Dt from"stream";import zr,{promisify as Gn}from"util";import{debuglog as Hn,promisify as Un}from"node:util";import et from"inquirer";import{of as Ot,concatMap as F,from as D,map as O,catchError as N,mergeMap as Kr,BehaviorSubject as Wr,ReplaySubject as zn,Subscription as Nt,lastValueFrom as Ft,toArray as _t,filter as Yr,Subject as Lt}from"rxjs";import _ from"fs/promises";import C from"chalk";import Kn from"@anthropic-ai/sdk";import{fromPromise as L}from"rxjs/internal/observable/innerFrom";import{xxh64 as Jr}from"@pacote/xxhash";import U from"winston";import"winston-daily-rotate-file";import Vr from"https";import Wn from"axios";import{CohereClientV2 as Yn}from"cohere-ai";import qr from"openai";import{GoogleGenerativeAI as Jn,HarmCategory as tt,HarmBlockThreshold as rt}from"@google/generative-ai";import Vn from"http";import qn from"net";import Xn from"tls";import Qn,{fileURLToPath as Zn,pathToFileURL as es}from"url";import Xr from"tty";import ts from"groq-sdk";import{Ollama as rs}from"ollama";import{fetch as os,Agent as ns}from"undici";import ot from"readline";import Qr from"figlet";import ss from"gradient-string";import Zr from"ora";import is from"inquirer-reactive-list-prompt";import{readdir as eo,stat as as,rm as cs}from"node:fs/promises";import ls from"chokidar";import{takeUntil as to,finalize as ro}from"rxjs/operators";var us="aicommit2",oo="2.4.27",ds="A Reactive CLI that generates commit messages for Git and Jujutsu with various AI",ms=["cli","ai","git","jujutsu","jj","vcs","version-control","commit","git-commit","jujutsu-commit","command-line","commandline","aipick","aicommit","aicommits","aicommit2","openai","huggingface","anthropic","claude","claude3","gemini","gemini-pro","generative-ai","mistral","ollama","llama3","llama3.2","llama3.3","gemma","llm","chatgpt","cohere","groq","codestral","perplexity","deepseek","deepseek-r1","pre-commit"],fs="MIT",ps="tak-bro/aicommit2",hs="Hyungtak Jin(@tak-bro)",gs="module",ys=["dist"],ws={aicommit2:"./dist/cli.mjs",aic2:"./dist/cli.mjs"},vs={prepare:"simple-git-hooks",build:"pkgroll --minify",lint:"eslint --cache .","type-check":"tsc",test:"tsx tests",prepack:"pnpm build && clean-pkg-json",prettier:"prettier"},Cs={"@anthropic-ai/sdk":"^0.39.0","@aws-sdk/client-bedrock-runtime":"^3.678.0","@aws-sdk/credential-providers":"^3.678.0","@dqbd/tiktoken":"^1.0.21","@google/generative-ai":"^0.24.1","@inquirer/prompts":"^3.3.2","@pacote/xxhash":"^0.3.2","@types/winston":"^2.4.4",axios:"^1.9.0",chalk:"^5.4.1",chokidar:"^4.0.3",cleye:"^1.3.4","cohere-ai":"^7.19.0","copy-paste":"^1.5.3",figlet:"^1.8.1","formdata-node":"^6.0.3","gradient-string":"^3.0.0","groq-sdk":"^0.7.0",inquirer:"9.2.8","inquirer-reactive-list-prompt":"^1.0.16",ollama:"^0.5.15",openai:"^6.3.0",ora:"^8.2.0",readline:"^1.3.0",rxjs:"^7.8.2",undici:"^7.10.0",uuid:"^9.0.1",winston:"^3.17.0","winston-daily-rotate-file":"^5.0.0"},bs={"@pvtnbr/eslint-config":"^0.33.0","@semantic-release/changelog":"^6.0.3","@semantic-release/commit-analyzer":"^12.0.0","@semantic-release/git":"^10.0.1","@semantic-release/github":"^10.3.5","@semantic-release/npm":"^12.0.1","@semantic-release/release-notes-generator":"^13.0.0","@types/figlet":"^1.7.0","@types/ini":"^1.3.34","@types/inquirer":"^9.0.8","@types/node":"^18.19.103","@types/uuid":"^9.0.8","@typescript-eslint/eslint-plugin":"^6.21.0","@typescript-eslint/parser":"^6.21.0","clean-pkg-json":"^1.3.0","conventional-changelog-conventionalcommits":"^7.0.2","conventional-commits-parser":"^5.0.0",eslint:"^8.57.1","eslint-config-prettier":"^8.10.0","eslint-plugin-eslint-comments":"^3.2.0","eslint-plugin-import":"^2.31.0","eslint-plugin-jsonc":"^2.20.1","eslint-plugin-no-use-extend-native":"^0.5.0","eslint-plugin-promise":"^6.6.0","eslint-plugin-unicorn":"^49.0.0","eslint-plugin-unused-imports":"^3.2.0",execa:"^7.2.0","fs-fixture":"^1.2.0","https-proxy-agent":"^5.0.1",ini:"^3.0.1","lint-staged":"^13.3.0",manten:"^0.7.0",pkgroll:"^1.11.1",prettier:"^3.5.3","semantic-release":"^23.1.1","simple-git-hooks":"^2.13.0",tsx:"^3.14.0",typescript:"^4.9.5","undici-types":"^7.10.0"},Es={extends:["@pvtnbr","prettier"],rules:{"unicorn/no-process-exit":"off"},overrides:[{files:"./src/commands/prepare-commit-msg-hook.ts",rules:{"unicorn/prevent-abbreviations":"off"}}]},Ps={branches:["main"],plugins:[["@semantic-release/commit-analyzer",{preset:"conventionalcommits",releaseRules:[{type:"refactor",release:"patch"},{type:"chore",release:"patch"},{type:"feat",release:"patch"},{scope:"major",release:"major"},{scope:"minor",release:"minor"},{scope:"patch",release:"patch"}]}],"@semantic-release/release-notes-generator",["@semantic-release/changelog",{changelogFile:"CHANGELOG.md"}],"@semantic-release/github",["@semantic-release/git",{assets:["CHANGELOG.md"],message:"chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"}],"@semantic-release/npm"]},$s={name:us,version:oo,description:ds,keywords:ms,license:fs,repository:ps,author:hs,type:gs,files:ys,bin:ws,scripts:vs,"simple-git-hooks":{"pre-commit":"pnpm lint-staged"},"lint-staged":{"*.ts":["prettier --config ./.prettierrc --write","eslint --fix"]},dependencies:Cs,devDependencies:bs,eslintConfig:Es,release:Ps},As=Rn(import.meta.url),H=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function Ee(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var Pe={exports:{}},Tt,no;function ks(){if(no)return Tt;no=1,Tt=o,o.sync=n;var t=X;function e(s,i){var l=i.pathExt!==void 0?i.pathExt:process.env.PATHEXT;if(!l||(l=l.split(";"),l.indexOf("")!==-1))return!0;for(var a=0;a<l.length;a++){var d=l[a].toLowerCase();if(d&&s.substr(-d.length).toLowerCase()===d)return!0}return!1}function r(s,i,l){return!s.isSymbolicLink()&&!s.isFile()?!1:e(i,l)}function o(s,i,l){t.stat(s,function(a,d){l(a,a?!1:r(d,s,i))})}function n(s,i){return r(t.statSync(s),s,i)}return Tt}var jt,so;function Ss(){if(so)return jt;so=1,jt=e,e.sync=r;var t=X;function e(s,i,l){t.stat(s,function(a,d){l(a,a?!1:o(d,i))})}function r(s,i){return o(t.statSync(s),i)}function o(s,i){return s.isFile()&&n(s,i)}function n(s,i){var l=s.mode,a=s.uid,d=s.gid,c=i.uid!==void 0?i.uid:process.getuid&&process.getuid(),u=i.gid!==void 0?i.gid:process.getgid&&process.getgid(),f=parseInt("100",8),p=parseInt("010",8),h=parseInt("001",8),g=f|p,y=l&h||l&p&&d===u||l&f&&a===c||l&g&&c===0;return y}return jt}var nt;process.platform==="win32"||H.TESTING_WINDOWS?nt=ks():nt=Ss();var xs=Bt;Bt.sync=Is;function Bt(t,e,r){if(typeof e=="function"&&(r=e,e={}),!r){if(typeof Promise!="function")throw new TypeError("callback not provided");return new Promise(function(o,n){Bt(t,e||{},function(s,i){s?n(s):o(i)})})}nt(t,e||{},function(o,n){o&&(o.code==="EACCES"||e&&e.ignoreErrors)&&(o=null,n=!1),r(o,n)})}function Is(t,e){try{return nt.sync(t,e||{})}catch(r){if(e&&e.ignoreErrors||r.code==="EACCES")return!1;throw r}}const $e=process.platform==="win32"||process.env.OSTYPE==="cygwin"||process.env.OSTYPE==="msys",io=x,Ms=$e?";":":",ao=xs,co=t=>Object.assign(new Error(`not found: ${t}`),{code:"ENOENT"}),lo=(t,e)=>{const r=e.colon||Ms,o=t.match(/\//)||$e&&t.match(/\\/)?[""]:[...$e?[process.cwd()]:[],...(e.path||process.env.PATH||"").split(r)],n=$e?e.pathExt||process.env.PATHEXT||".EXE;.CMD;.BAT;.COM":"",s=$e?n.split(r):[""];return $e&&t.indexOf(".")!==-1&&s[0]!==""&&s.unshift(""),{pathEnv:o,pathExt:s,pathExtExe:n}},uo=(t,e,r)=>{typeof e=="function"&&(r=e,e={}),e||(e={});const{pathEnv:o,pathExt:n,pathExtExe:s}=lo(t,e),i=[],l=d=>new Promise((c,u)=>{if(d===o.length)return e.all&&i.length?c(i):u(co(t));const f=o[d],p=/^".*"$/.test(f)?f.slice(1,-1):f,h=io.join(p,t),g=!p&&/^\.[\\\/]/.test(t)?t.slice(0,2)+h:h;c(a(g,d,0))}),a=(d,c,u)=>new Promise((f,p)=>{if(u===n.length)return f(l(c+1));const h=n[u];ao(d+h,{pathExt:s},(g,y)=>{if(!g&&y)if(e.all)i.push(d+h);else return f(d+h);return f(a(d,c,u+1))})});return r?l(0).then(d=>r(null,d),r):l(0)},Rs=(t,e)=>{e=e||{};const{pathEnv:r,pathExt:o,pathExtExe:n}=lo(t,e),s=[];for(let i=0;i<r.length;i++){const l=r[i],a=/^".*"$/.test(l)?l.slice(1,-1):l,d=io.join(a,t),c=!a&&/^\.[\\\/]/.test(t)?t.slice(0,2)+d:d;for(let u=0;u<o.length;u++){const f=c+o[u];try{if(ao.sync(f,{pathExt:n}))if(e.all)s.push(f);else return f}catch{}}}if(e.all&&s.length)return s;if(e.nothrow)return null;throw co(t)};var Ds=uo;uo.sync=Rs;var Gt={exports:{}};const mo=(t={})=>{const e=t.env||process.env;return(t.platform||process.platform)!=="win32"?"PATH":Object.keys(e).reverse().find(o=>o.toUpperCase()==="PATH")||"Path"};Gt.exports=mo,Gt.exports.default=mo;var Os=Gt.exports;const fo=x,Ns=Ds,Fs=Os;function po(t,e){const r=t.options.env||process.env,o=process.cwd(),n=t.options.cwd!=null,s=n&&process.chdir!==void 0&&!process.chdir.disabled;if(s)try{process.chdir(t.options.cwd)}catch{}let i;try{i=Ns.sync(t.command,{path:r[Fs({env:r})],pathExt:e?fo.delimiter:void 0})}catch{}finally{s&&process.chdir(o)}return i&&(i=fo.resolve(n?t.options.cwd:"",i)),i}function _s(t){return po(t)||po(t,!0)}var Ls=_s,Ht={};const Ut=/([()\][%!^"`<>&|;, *?])/g;function Ts(t){return t=t.replace(Ut,"^$1"),t}function js(t,e){return t=`${t}`,t=t.replace(/(?=(\\+?)?)\1"/g,'$1$1\\"'),t=t.replace(/(?=(\\+?)?)\1$/,"$1$1"),t=`"${t}"`,t=t.replace(Ut,"^$1"),e&&(t=t.replace(Ut,"^$1")),t}Ht.command=Ts,Ht.argument=js;var Bs=/^#!(.*)/;const Gs=Bs;var Hs=(t="")=>{const e=t.match(Gs);if(!e)return null;const[r,o]=e[0].replace(/#! ?/,"").split(" "),n=r.split("/").pop();return n==="env"?o:o?`${n} ${o}`:n};const zt=X,Us=Hs;function zs(t){const r=Buffer.alloc(150);let o;try{o=zt.openSync(t,"r"),zt.readSync(o,r,0,150,0),zt.closeSync(o)}catch{}return Us(r.toString())}var Ks=zs;const Ws=x,ho=Ls,go=Ht,Ys=Ks,Js=process.platform==="win32",Vs=/\.(?:com|exe)$/i,qs=/node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;function Xs(t){t.file=ho(t);const e=t.file&&Ys(t.file);return e?(t.args.unshift(t.file),t.command=e,ho(t)):t.file}function Qs(t){if(!Js)return t;const e=Xs(t),r=!Vs.test(e);if(t.options.forceShell||r){const o=qs.test(e);t.command=Ws.normalize(t.command),t.command=go.command(t.command),t.args=t.args.map(s=>go.argument(s,o));const n=[t.command].concat(t.args).join(" ");t.args=["/d","/s","/c",`"${n}"`],t.command=process.env.comspec||"cmd.exe",t.options.windowsVerbatimArguments=!0}return t}function Zs(t,e,r){e&&!Array.isArray(e)&&(r=e,e=null),e=e?e.slice(0):[],r=Object.assign({},r);const o={command:t,args:e,options:r,file:void 0,original:{command:t,args:e}};return r.shell?o:Qs(o)}var ei=Zs;const Kt=process.platform==="win32";function Wt(t,e){return Object.assign(new Error(`${e} ${t.command} ENOENT`),{code:"ENOENT",errno:"ENOENT",syscall:`${e} ${t.command}`,path:t.command,spawnargs:t.args})}function ti(t,e){if(!Kt)return;const r=t.emit;t.emit=function(o,n){if(o==="exit"){const s=yo(n,e);if(s)return r.call(t,"error",s)}return r.apply(t,arguments)}}function yo(t,e){return Kt&&t===1&&!e.file?Wt(e.original,"spawn"):null}function ri(t,e){return Kt&&t===1&&!e.file?Wt(e.original,"spawnSync"):null}var oi={hookChildProcess:ti,verifyENOENT:yo,verifyENOENTSync:ri,notFoundError:Wt};const wo=Nn,Yt=ei,Jt=oi;function vo(t,e,r){const o=Yt(t,e,r),n=wo.spawn(o.command,o.args,o.options);return Jt.hookChildProcess(n,o),n}function ni(t,e,r){const o=Yt(t,e,r),n=wo.spawnSync(o.command,o.args,o.options);return n.error=n.error||Jt.verifyENOENTSync(n.status,o),n}Pe.exports=vo,Pe.exports.spawn=vo,Pe.exports.sync=ni,Pe.exports._parse=Yt,Pe.exports._enoent=Jt;var si=Pe.exports,ii=Ee(si);function ai(t){const e=typeof t=="string"?`
2
+ import{command as de,cli as Mn}from"cleye";import{createRequire as Rn}from"module";import Dn from"crypto";import X from"fs";import Fe from"os";import x from"path";import{Buffer as Tr}from"node:buffer";import ge from"node:path";import Rt,{ChildProcess as jr,exec as On}from"node:child_process";import ae from"node:process";import Nn,{execSync as Ze,exec as Fn}from"child_process";import{fileURLToPath as Br}from"node:url";import _n,{constants as Gr}from"node:os";import Hr from"assert";import Ur from"events";import{createWriteStream as Ln,createReadStream as Tn,readFileSync as jn}from"node:fs";import Bn from"buffer";import Dt from"stream";import zr,{promisify as Gn}from"util";import{debuglog as Hn,promisify as Un}from"node:util";import et from"inquirer";import{of as Ot,concatMap as F,from as D,map as O,catchError as N,mergeMap as Kr,BehaviorSubject as Wr,ReplaySubject as zn,Subscription as Nt,lastValueFrom as Ft,toArray as _t,filter as Yr,Subject as Lt}from"rxjs";import _ from"fs/promises";import C from"chalk";import Kn from"@anthropic-ai/sdk";import{fromPromise as L}from"rxjs/internal/observable/innerFrom";import{xxh64 as Jr}from"@pacote/xxhash";import U from"winston";import"winston-daily-rotate-file";import Vr from"https";import Wn from"axios";import{CohereClientV2 as Yn}from"cohere-ai";import qr from"openai";import{GoogleGenerativeAI as Jn,HarmCategory as tt,HarmBlockThreshold as rt}from"@google/generative-ai";import Vn from"http";import qn from"net";import Xn from"tls";import Qn,{fileURLToPath as Zn,pathToFileURL as es}from"url";import Xr from"tty";import ts from"groq-sdk";import{Ollama as rs}from"ollama";import{fetch as os,Agent as ns}from"undici";import ot from"readline";import Qr from"figlet";import ss from"gradient-string";import Zr from"ora";import is from"inquirer-reactive-list-prompt";import{readdir as eo,stat as as,rm as cs}from"node:fs/promises";import ls from"chokidar";import{takeUntil as to,finalize as ro}from"rxjs/operators";var us="aicommit2",oo="2.4.28",ds="A Reactive CLI that generates commit messages for Git and Jujutsu with various AI",ms=["cli","ai","git","jujutsu","jj","vcs","version-control","commit","git-commit","jujutsu-commit","command-line","commandline","aipick","aicommit","aicommits","aicommit2","openai","huggingface","anthropic","claude","claude3","gemini","gemini-pro","generative-ai","mistral","ollama","llama3","llama3.2","llama3.3","gemma","llm","chatgpt","cohere","groq","codestral","perplexity","deepseek","deepseek-r1","pre-commit"],fs="MIT",ps="tak-bro/aicommit2",hs="Hyungtak Jin(@tak-bro)",gs="module",ys=["dist"],ws={aicommit2:"./dist/cli.mjs",aic2:"./dist/cli.mjs"},vs={prepare:"simple-git-hooks",build:"pkgroll --minify",lint:"eslint --cache .","type-check":"tsc",test:"tsx tests",prepack:"pnpm build && clean-pkg-json",prettier:"prettier"},Cs={"@anthropic-ai/sdk":"^0.39.0","@aws-sdk/client-bedrock-runtime":"^3.678.0","@aws-sdk/credential-providers":"^3.678.0","@dqbd/tiktoken":"^1.0.21","@google/generative-ai":"^0.24.1","@inquirer/prompts":"^3.3.2","@pacote/xxhash":"^0.3.2","@types/winston":"^2.4.4",axios:"^1.9.0",chalk:"^5.4.1",chokidar:"^4.0.3",cleye:"^1.3.4","cohere-ai":"^7.19.0","copy-paste":"^1.5.3",figlet:"^1.8.1","formdata-node":"^6.0.3","gradient-string":"^3.0.0","groq-sdk":"^0.7.0",inquirer:"9.2.8","inquirer-reactive-list-prompt":"^1.0.16",ollama:"^0.5.15",openai:"^6.3.0",ora:"^8.2.0",readline:"^1.3.0",rxjs:"^7.8.2",undici:"^7.10.0",uuid:"^9.0.1",winston:"^3.17.0","winston-daily-rotate-file":"^5.0.0"},bs={"@pvtnbr/eslint-config":"^0.33.0","@semantic-release/changelog":"^6.0.3","@semantic-release/commit-analyzer":"^12.0.0","@semantic-release/git":"^10.0.1","@semantic-release/github":"^10.3.5","@semantic-release/npm":"^12.0.1","@semantic-release/release-notes-generator":"^13.0.0","@types/figlet":"^1.7.0","@types/ini":"^1.3.34","@types/inquirer":"^9.0.8","@types/node":"^18.19.103","@types/uuid":"^9.0.8","@typescript-eslint/eslint-plugin":"^6.21.0","@typescript-eslint/parser":"^6.21.0","clean-pkg-json":"^1.3.0","conventional-changelog-conventionalcommits":"^7.0.2","conventional-commits-parser":"^5.0.0",eslint:"^8.57.1","eslint-config-prettier":"^8.10.0","eslint-plugin-eslint-comments":"^3.2.0","eslint-plugin-import":"^2.31.0","eslint-plugin-jsonc":"^2.20.1","eslint-plugin-no-use-extend-native":"^0.5.0","eslint-plugin-promise":"^6.6.0","eslint-plugin-unicorn":"^49.0.0","eslint-plugin-unused-imports":"^3.2.0",execa:"^7.2.0","fs-fixture":"^1.2.0","https-proxy-agent":"^5.0.1",ini:"^3.0.1","lint-staged":"^13.3.0",manten:"^0.7.0",pkgroll:"^1.11.1",prettier:"^3.5.3","semantic-release":"^23.1.1","simple-git-hooks":"^2.13.0",tsx:"^3.14.0",typescript:"^4.9.5","undici-types":"^7.10.0"},Es={extends:["@pvtnbr","prettier"],rules:{"unicorn/no-process-exit":"off"},overrides:[{files:"./src/commands/prepare-commit-msg-hook.ts",rules:{"unicorn/prevent-abbreviations":"off"}}]},Ps={branches:["main"],plugins:[["@semantic-release/commit-analyzer",{preset:"conventionalcommits",releaseRules:[{type:"refactor",release:"patch"},{type:"chore",release:"patch"},{type:"feat",release:"patch"},{scope:"major",release:"major"},{scope:"minor",release:"minor"},{scope:"patch",release:"patch"}]}],"@semantic-release/release-notes-generator",["@semantic-release/changelog",{changelogFile:"CHANGELOG.md"}],"@semantic-release/github",["@semantic-release/git",{assets:["CHANGELOG.md"],message:"chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"}],"@semantic-release/npm"]},$s={name:us,version:oo,description:ds,keywords:ms,license:fs,repository:ps,author:hs,type:gs,files:ys,bin:ws,scripts:vs,"simple-git-hooks":{"pre-commit":"pnpm lint-staged"},"lint-staged":{"*.ts":["prettier --config ./.prettierrc --write","eslint --fix"]},dependencies:Cs,devDependencies:bs,eslintConfig:Es,release:Ps},As=Rn(import.meta.url),H=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function Ee(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var Pe={exports:{}},Tt,no;function ks(){if(no)return Tt;no=1,Tt=o,o.sync=n;var t=X;function e(s,i){var l=i.pathExt!==void 0?i.pathExt:process.env.PATHEXT;if(!l||(l=l.split(";"),l.indexOf("")!==-1))return!0;for(var a=0;a<l.length;a++){var d=l[a].toLowerCase();if(d&&s.substr(-d.length).toLowerCase()===d)return!0}return!1}function r(s,i,l){return!s.isSymbolicLink()&&!s.isFile()?!1:e(i,l)}function o(s,i,l){t.stat(s,function(a,d){l(a,a?!1:r(d,s,i))})}function n(s,i){return r(t.statSync(s),s,i)}return Tt}var jt,so;function Ss(){if(so)return jt;so=1,jt=e,e.sync=r;var t=X;function e(s,i,l){t.stat(s,function(a,d){l(a,a?!1:o(d,i))})}function r(s,i){return o(t.statSync(s),i)}function o(s,i){return s.isFile()&&n(s,i)}function n(s,i){var l=s.mode,a=s.uid,d=s.gid,c=i.uid!==void 0?i.uid:process.getuid&&process.getuid(),u=i.gid!==void 0?i.gid:process.getgid&&process.getgid(),f=parseInt("100",8),p=parseInt("010",8),h=parseInt("001",8),g=f|p,y=l&h||l&p&&d===u||l&f&&a===c||l&g&&c===0;return y}return jt}var nt;process.platform==="win32"||H.TESTING_WINDOWS?nt=ks():nt=Ss();var xs=Bt;Bt.sync=Is;function Bt(t,e,r){if(typeof e=="function"&&(r=e,e={}),!r){if(typeof Promise!="function")throw new TypeError("callback not provided");return new Promise(function(o,n){Bt(t,e||{},function(s,i){s?n(s):o(i)})})}nt(t,e||{},function(o,n){o&&(o.code==="EACCES"||e&&e.ignoreErrors)&&(o=null,n=!1),r(o,n)})}function Is(t,e){try{return nt.sync(t,e||{})}catch(r){if(e&&e.ignoreErrors||r.code==="EACCES")return!1;throw r}}const $e=process.platform==="win32"||process.env.OSTYPE==="cygwin"||process.env.OSTYPE==="msys",io=x,Ms=$e?";":":",ao=xs,co=t=>Object.assign(new Error(`not found: ${t}`),{code:"ENOENT"}),lo=(t,e)=>{const r=e.colon||Ms,o=t.match(/\//)||$e&&t.match(/\\/)?[""]:[...$e?[process.cwd()]:[],...(e.path||process.env.PATH||"").split(r)],n=$e?e.pathExt||process.env.PATHEXT||".EXE;.CMD;.BAT;.COM":"",s=$e?n.split(r):[""];return $e&&t.indexOf(".")!==-1&&s[0]!==""&&s.unshift(""),{pathEnv:o,pathExt:s,pathExtExe:n}},uo=(t,e,r)=>{typeof e=="function"&&(r=e,e={}),e||(e={});const{pathEnv:o,pathExt:n,pathExtExe:s}=lo(t,e),i=[],l=d=>new Promise((c,u)=>{if(d===o.length)return e.all&&i.length?c(i):u(co(t));const f=o[d],p=/^".*"$/.test(f)?f.slice(1,-1):f,h=io.join(p,t),g=!p&&/^\.[\\\/]/.test(t)?t.slice(0,2)+h:h;c(a(g,d,0))}),a=(d,c,u)=>new Promise((f,p)=>{if(u===n.length)return f(l(c+1));const h=n[u];ao(d+h,{pathExt:s},(g,y)=>{if(!g&&y)if(e.all)i.push(d+h);else return f(d+h);return f(a(d,c,u+1))})});return r?l(0).then(d=>r(null,d),r):l(0)},Rs=(t,e)=>{e=e||{};const{pathEnv:r,pathExt:o,pathExtExe:n}=lo(t,e),s=[];for(let i=0;i<r.length;i++){const l=r[i],a=/^".*"$/.test(l)?l.slice(1,-1):l,d=io.join(a,t),c=!a&&/^\.[\\\/]/.test(t)?t.slice(0,2)+d:d;for(let u=0;u<o.length;u++){const f=c+o[u];try{if(ao.sync(f,{pathExt:n}))if(e.all)s.push(f);else return f}catch{}}}if(e.all&&s.length)return s;if(e.nothrow)return null;throw co(t)};var Ds=uo;uo.sync=Rs;var Gt={exports:{}};const mo=(t={})=>{const e=t.env||process.env;return(t.platform||process.platform)!=="win32"?"PATH":Object.keys(e).reverse().find(o=>o.toUpperCase()==="PATH")||"Path"};Gt.exports=mo,Gt.exports.default=mo;var Os=Gt.exports;const fo=x,Ns=Ds,Fs=Os;function po(t,e){const r=t.options.env||process.env,o=process.cwd(),n=t.options.cwd!=null,s=n&&process.chdir!==void 0&&!process.chdir.disabled;if(s)try{process.chdir(t.options.cwd)}catch{}let i;try{i=Ns.sync(t.command,{path:r[Fs({env:r})],pathExt:e?fo.delimiter:void 0})}catch{}finally{s&&process.chdir(o)}return i&&(i=fo.resolve(n?t.options.cwd:"",i)),i}function _s(t){return po(t)||po(t,!0)}var Ls=_s,Ht={};const Ut=/([()\][%!^"`<>&|;, *?])/g;function Ts(t){return t=t.replace(Ut,"^$1"),t}function js(t,e){return t=`${t}`,t=t.replace(/(?=(\\+?)?)\1"/g,'$1$1\\"'),t=t.replace(/(?=(\\+?)?)\1$/,"$1$1"),t=`"${t}"`,t=t.replace(Ut,"^$1"),e&&(t=t.replace(Ut,"^$1")),t}Ht.command=Ts,Ht.argument=js;var Bs=/^#!(.*)/;const Gs=Bs;var Hs=(t="")=>{const e=t.match(Gs);if(!e)return null;const[r,o]=e[0].replace(/#! ?/,"").split(" "),n=r.split("/").pop();return n==="env"?o:o?`${n} ${o}`:n};const zt=X,Us=Hs;function zs(t){const r=Buffer.alloc(150);let o;try{o=zt.openSync(t,"r"),zt.readSync(o,r,0,150,0),zt.closeSync(o)}catch{}return Us(r.toString())}var Ks=zs;const Ws=x,ho=Ls,go=Ht,Ys=Ks,Js=process.platform==="win32",Vs=/\.(?:com|exe)$/i,qs=/node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;function Xs(t){t.file=ho(t);const e=t.file&&Ys(t.file);return e?(t.args.unshift(t.file),t.command=e,ho(t)):t.file}function Qs(t){if(!Js)return t;const e=Xs(t),r=!Vs.test(e);if(t.options.forceShell||r){const o=qs.test(e);t.command=Ws.normalize(t.command),t.command=go.command(t.command),t.args=t.args.map(s=>go.argument(s,o));const n=[t.command].concat(t.args).join(" ");t.args=["/d","/s","/c",`"${n}"`],t.command=process.env.comspec||"cmd.exe",t.options.windowsVerbatimArguments=!0}return t}function Zs(t,e,r){e&&!Array.isArray(e)&&(r=e,e=null),e=e?e.slice(0):[],r=Object.assign({},r);const o={command:t,args:e,options:r,file:void 0,original:{command:t,args:e}};return r.shell?o:Qs(o)}var ei=Zs;const Kt=process.platform==="win32";function Wt(t,e){return Object.assign(new Error(`${e} ${t.command} ENOENT`),{code:"ENOENT",errno:"ENOENT",syscall:`${e} ${t.command}`,path:t.command,spawnargs:t.args})}function ti(t,e){if(!Kt)return;const r=t.emit;t.emit=function(o,n){if(o==="exit"){const s=yo(n,e);if(s)return r.call(t,"error",s)}return r.apply(t,arguments)}}function yo(t,e){return Kt&&t===1&&!e.file?Wt(e.original,"spawn"):null}function ri(t,e){return Kt&&t===1&&!e.file?Wt(e.original,"spawnSync"):null}var oi={hookChildProcess:ti,verifyENOENT:yo,verifyENOENTSync:ri,notFoundError:Wt};const wo=Nn,Yt=ei,Jt=oi;function vo(t,e,r){const o=Yt(t,e,r),n=wo.spawn(o.command,o.args,o.options);return Jt.hookChildProcess(n,o),n}function ni(t,e,r){const o=Yt(t,e,r),n=wo.spawnSync(o.command,o.args,o.options);return n.error=n.error||Jt.verifyENOENTSync(n.status,o),n}Pe.exports=vo,Pe.exports.spawn=vo,Pe.exports.sync=ni,Pe.exports._parse=Yt,Pe.exports._enoent=Jt;var si=Pe.exports,ii=Ee(si);function ai(t){const e=typeof t=="string"?`
3
3
  `:`
4
4
  `.charCodeAt(),r=typeof t=="string"?"\r":"\r".charCodeAt();return t[t.length-1]===e&&(t=t.slice(0,-1)),t[t.length-1]===r&&(t=t.slice(0,-1)),t}function Co(t={}){const{env:e=process.env,platform:r=process.platform}=t;return r!=="win32"?"PATH":Object.keys(e).reverse().find(o=>o.toUpperCase()==="PATH")||"Path"}const ci=({cwd:t=ae.cwd(),path:e=ae.env[Co()],preferLocal:r=!0,execPath:o=ae.execPath,addExecPath:n=!0}={})=>{const s=t instanceof URL?Br(t):t,i=ge.resolve(s),l=[];return r&&li(l,i),n&&ui(l,o,i),[...l,e].join(ge.delimiter)},li=(t,e)=>{let r;for(;r!==e;)t.push(ge.join(e,"node_modules/.bin")),r=e,e=ge.resolve(e,"..")},ui=(t,e,r)=>{const o=e instanceof URL?Br(e):e;t.push(ge.resolve(r,o,".."))},di=({env:t=ae.env,...e}={})=>{t={...t};const r=Co({env:t});return e.path=t[r],t[r]=ci(e),t},mi=(t,e,r,o)=>{if(r==="length"||r==="prototype"||r==="arguments"||r==="caller")return;const n=Object.getOwnPropertyDescriptor(t,r),s=Object.getOwnPropertyDescriptor(e,r);!fi(n,s)&&o||Object.defineProperty(t,r,s)},fi=function(t,e){return t===void 0||t.configurable||t.writable===e.writable&&t.enumerable===e.enumerable&&t.configurable===e.configurable&&(t.writable||t.value===e.value)},pi=(t,e)=>{const r=Object.getPrototypeOf(e);r!==Object.getPrototypeOf(t)&&Object.setPrototypeOf(t,r)},hi=(t,e)=>`/* Wrapped ${t}*/
5
5
  ${e}`,gi=Object.getOwnPropertyDescriptor(Function.prototype,"toString"),yi=Object.getOwnPropertyDescriptor(Function.prototype.toString,"name"),wi=(t,e,r)=>{const o=r===""?"":`with ${r.trim()}() `,n=hi.bind(null,o,e.toString());Object.defineProperty(n,"name",yi),Object.defineProperty(t,"toString",{...gi,value:n})};function vi(t,e,{ignoreNonConfigurable:r=!1}={}){const{name:o}=t;for(const n of Reflect.ownKeys(e))mi(t,e,n,r);return pi(t,e),wi(t,e,o),t}const st=new WeakMap,bo=(t,e={})=>{if(typeof t!="function")throw new TypeError("Expected a function");let r,o=0;const n=t.displayName||t.name||"<anonymous>",s=function(...i){if(st.set(s,++o),o===1)r=t.apply(this,i),t=null;else if(e.throw===!0)throw new Error(`Function \`${n}\` can only be called once`);return r};return vi(s,t),st.set(s,o),s};bo.callCount=t=>{if(!st.has(t))throw new Error(`The given function \`${t.name}\` is not wrapped by the \`onetime\` package`);return st.get(t)};const Ci=()=>{const t=Po-Eo+1;return Array.from({length:t},bi)},bi=(t,e)=>({name:`SIGRT${e+1}`,number:Eo+e,action:"terminate",description:"Application-specific signal (realtime)",standard:"posix"}),Eo=34,Po=64,Ei=[{name:"SIGHUP",number:1,action:"terminate",description:"Terminal closed",standard:"posix"},{name:"SIGINT",number:2,action:"terminate",description:"User interruption with CTRL-C",standard:"ansi"},{name:"SIGQUIT",number:3,action:"core",description:"User interruption with CTRL-\\",standard:"posix"},{name:"SIGILL",number:4,action:"core",description:"Invalid machine instruction",standard:"ansi"},{name:"SIGTRAP",number:5,action:"core",description:"Debugger breakpoint",standard:"posix"},{name:"SIGABRT",number:6,action:"core",description:"Aborted",standard:"ansi"},{name:"SIGIOT",number:6,action:"core",description:"Aborted",standard:"bsd"},{name:"SIGBUS",number:7,action:"core",description:"Bus error due to misaligned, non-existing address or paging error",standard:"bsd"},{name:"SIGEMT",number:7,action:"terminate",description:"Command should be emulated but is not implemented",standard:"other"},{name:"SIGFPE",number:8,action:"core",description:"Floating point arithmetic error",standard:"ansi"},{name:"SIGKILL",number:9,action:"terminate",description:"Forced termination",standard:"posix",forced:!0},{name:"SIGUSR1",number:10,action:"terminate",description:"Application-specific signal",standard:"posix"},{name:"SIGSEGV",number:11,action:"core",description:"Segmentation fault",standard:"ansi"},{name:"SIGUSR2",number:12,action:"terminate",description:"Application-specific signal",standard:"posix"},{name:"SIGPIPE",number:13,action:"terminate",description:"Broken pipe or socket",standard:"posix"},{name:"SIGALRM",number:14,action:"terminate",description:"Timeout or timer",standard:"posix"},{name:"SIGTERM",number:15,action:"terminate",description:"Termination",standard:"ansi"},{name:"SIGSTKFLT",number:16,action:"terminate",description:"Stack is empty or overflowed",standard:"other"},{name:"SIGCHLD",number:17,action:"ignore",description:"Child process terminated, paused or unpaused",standard:"posix"},{name:"SIGCLD",number:17,action:"ignore",description:"Child process terminated, paused or unpaused",standard:"other"},{name:"SIGCONT",number:18,action:"unpause",description:"Unpaused",standard:"posix",forced:!0},{name:"SIGSTOP",number:19,action:"pause",description:"Paused",standard:"posix",forced:!0},{name:"SIGTSTP",number:20,action:"pause",description:'Paused using CTRL-Z or "suspend"',standard:"posix"},{name:"SIGTTIN",number:21,action:"pause",description:"Background process cannot read terminal input",standard:"posix"},{name:"SIGBREAK",number:21,action:"terminate",description:"User interruption with CTRL-BREAK",standard:"other"},{name:"SIGTTOU",number:22,action:"pause",description:"Background process cannot write to terminal output",standard:"posix"},{name:"SIGURG",number:23,action:"ignore",description:"Socket received out-of-band data",standard:"bsd"},{name:"SIGXCPU",number:24,action:"core",description:"Process timed out",standard:"bsd"},{name:"SIGXFSZ",number:25,action:"core",description:"File too big",standard:"bsd"},{name:"SIGVTALRM",number:26,action:"terminate",description:"Timeout or timer",standard:"bsd"},{name:"SIGPROF",number:27,action:"terminate",description:"Timeout or timer",standard:"bsd"},{name:"SIGWINCH",number:28,action:"ignore",description:"Terminal window size changed",standard:"bsd"},{name:"SIGIO",number:29,action:"terminate",description:"I/O is available",standard:"other"},{name:"SIGPOLL",number:29,action:"terminate",description:"Watched event",standard:"other"},{name:"SIGINFO",number:29,action:"ignore",description:"Request for process information",standard:"other"},{name:"SIGPWR",number:30,action:"terminate",description:"Device running out of power",standard:"systemv"},{name:"SIGSYS",number:31,action:"core",description:"Invalid system call",standard:"other"},{name:"SIGUNUSED",number:31,action:"terminate",description:"Invalid system call",standard:"other"}],$o=()=>{const t=Ci();return[...Ei,...t].map(Pi)},Pi=({name:t,number:e,description:r,action:o,forced:n=!1,standard:s})=>{const{signals:{[t]:i}}=Gr,l=i!==void 0;return{name:t,number:l?i:e,description:r,supported:l,action:o,forced:n,standard:s}},$i=()=>{const t=$o();return Object.fromEntries(t.map(Ai))},Ai=({name:t,number:e,description:r,supported:o,action:n,forced:s,standard:i})=>[t,{name:t,number:e,description:r,supported:o,action:n,forced:s,standard:i}],ki=$i(),Si=()=>{const t=$o(),e=Po+1,r=Array.from({length:e},(o,n)=>xi(n,t));return Object.assign({},...r)},xi=(t,e)=>{const r=Ii(t,e);if(r===void 0)return{};const{name:o,description:n,supported:s,action:i,forced:l,standard:a}=r;return{[t]:{name:o,number:t,description:n,supported:s,action:i,forced:l,standard:a}}},Ii=(t,e)=>{const r=e.find(({name:o})=>Gr.signals[o]===t);return r!==void 0?r:e.find(o=>o.number===t)};Si();const Mi=({timedOut:t,timeout:e,errorCode:r,signal:o,signalDescription:n,exitCode:s,isCanceled:i})=>t?`timed out after ${e} milliseconds`:i?"was canceled":r!==void 0?`failed with ${r}`:o!==void 0?`was killed with ${o} (${n})`:s!==void 0?`failed with exit code ${s}`:"failed",it=({stdout:t,stderr:e,all:r,error:o,signal:n,exitCode:s,command:i,escapedCommand:l,timedOut:a,isCanceled:d,killed:c,parsed:{options:{timeout:u,cwd:f=ae.cwd()}}})=>{s=s===null?void 0:s,n=n===null?void 0:n;const p=n===void 0?void 0:ki[n].description,h=o&&o.code,y=`Command ${Mi({timedOut:a,timeout:u,errorCode:h,signal:n,signalDescription:p,exitCode:s,isCanceled:d})}: ${i}`,v=Object.prototype.toString.call(o)==="[object Error]",E=v?`${y}
@@ -123,7 +123,7 @@ Please install Jujutsu:
123
123
  - macOS: brew install jj
124
124
  - Linux: cargo install jj-cli
125
125
  - Windows: cargo install jj-cli
126
- - See: https://github.com/martinvonz/jj#installation`):new w(`Failed to execute jj command: ${r.message}`)}try{const{stdout:e,stderr:r}=await S("jj",["workspace","root"],{reject:!0}),o=e.trim();if(!o)throw new w("jj workspace root returned empty path");const n=x.join(o,".jj");if(!X.existsSync(n))throw new w(`Jujutsu repository directory not found at ${n}
126
+ - See: https://github.com/jj-vcs/jj#installation`):new w(`Failed to execute jj command: ${r.message}`)}try{const{stdout:e,stderr:r}=await S("jj",["workspace","root"],{reject:!0}),o=e.trim();if(!o)throw new w("jj workspace root returned empty path");const n=x.join(o,".jj");if(!X.existsSync(n))throw new w(`Jujutsu repository directory not found at ${n}
127
127
 
128
128
  Initialize a jj repository with: jj init`);return o}catch(e){if(e instanceof w)throw e;const r=e;throw r.stderr?r.stderr.includes("not in a jj repo")?new w(`Not in a Jujutsu repository!
129
129
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aicommit2",
3
- "version": "2.4.27",
3
+ "version": "2.4.28",
4
4
  "description": "A Reactive CLI that generates commit messages for Git and Jujutsu with various AI",
5
5
  "keywords": [
6
6
  "cli",