@johnowennixon/diffdash 1.12.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -8
- package/dist/package.json +12 -12
- package/dist/src/lib_ansi.js +0 -1
- package/dist/src/lib_cli.js +50 -28
- package/dist/src/lib_debug.js +2 -1
- package/dist/src/lib_diffdash_cli.js +31 -24
- package/dist/src/lib_diffdash_config.js +6 -3
- package/dist/src/lib_diffdash_llm.js +4 -4
- package/dist/src/lib_diffdash_sequence.js +4 -4
- package/dist/src/lib_git_message_prompt.js +6 -4
- package/dist/src/lib_language.js +59 -0
- package/dist/src/lib_llm_model.js +88 -68
- package/dist/src/lib_secret_check.js +5 -5
- package/package.json +12 -12
- package/dist/src/lib_string_types.js +0 -1
package/README.md
CHANGED
|
@@ -11,9 +11,10 @@ A command-line tool to generate Git commit messages using AI.
|
|
|
11
11
|
|
|
12
12
|
## Features
|
|
13
13
|
|
|
14
|
-
* Generate Git commit messages in
|
|
15
|
-
* Add a prefix or suffix to the summary line
|
|
16
|
-
* Add a footer to the generated commit messages
|
|
14
|
+
* Generate Git commit messages in natural language prose
|
|
15
|
+
* Add a prefix or suffix to the summary line to support tickets from project management tools
|
|
16
|
+
* Add a metadata footer to the generated commit messages
|
|
17
|
+
* Support for 42 human languages including English, Chinese, and Hindi
|
|
17
18
|
* Select from a choice of LLM models
|
|
18
19
|
* Compare messages generated from all configured models
|
|
19
20
|
* Disable or auto-approve various stages
|
|
@@ -21,7 +22,7 @@ A command-line tool to generate Git commit messages using AI.
|
|
|
21
22
|
* Configuration using standard API provider environment variables
|
|
22
23
|
* Uses the Vercel AI SDK (version 6)
|
|
23
24
|
* Uses structured JSON with compatible models
|
|
24
|
-
* Substantially written using AI coding (Claude Code, Roo Code, and Amp)
|
|
25
|
+
* Substantially written using AI coding (Claude Code, Roo Code, and Amp Code)
|
|
25
26
|
|
|
26
27
|
## Installation from npmjs.com
|
|
27
28
|
|
|
@@ -31,13 +32,10 @@ npm install -g @johnowennixon/diffdash
|
|
|
31
32
|
|
|
32
33
|
## LLM Models
|
|
33
34
|
|
|
34
|
-
Currently, for this application, the best LLM model is **gpt-
|
|
35
|
+
Currently, for this application, the best LLM model is **gpt-5-mini-minimal** (GPT-5 Mini with reasoning disabled) from OpenAI.
|
|
35
36
|
It is set as the default model.
|
|
36
37
|
I can only presume they have done a ton of training on diffs.
|
|
37
38
|
|
|
38
|
-
I have tested the GPT-5 models and **gpt-5-mini-minimal** (GPT-5 Mini with reasoning disabled) is behaving much the same.
|
|
39
|
-
It will become the default model if gpt-4.1-mini is deprecated.
|
|
40
|
-
|
|
41
39
|
## API Keys
|
|
42
40
|
|
|
43
41
|
DiffDash requires at least one API key for an LLM provider. These must be provided as environment variables.
|
|
@@ -98,6 +96,9 @@ diffdash --add-prefix "[FIX]"
|
|
|
98
96
|
# Add a suffix to the commit message summary line
|
|
99
97
|
diffdash --add-suffix "(closes #DEV-1234)"
|
|
100
98
|
|
|
99
|
+
# Generate commit message in a different language
|
|
100
|
+
diffdash --language af # Afrikaans
|
|
101
|
+
|
|
101
102
|
# Display commit messages generated by all models
|
|
102
103
|
diffdash --llm-compare
|
|
103
104
|
|
|
@@ -129,6 +130,7 @@ All command-line arguments are optional.
|
|
|
129
130
|
| `--disable-push` | disable pushing changes - exit after making the commit |
|
|
130
131
|
| `--add-prefix PREFIX` | add a prefix to the commit message summary line |
|
|
131
132
|
| `--add-suffix SUFFIX` | add a suffix to the commit message summary line |
|
|
133
|
+
| `--language CODE` | choose the language for commit messages (defaults to 'en' for English) |
|
|
132
134
|
| `--llm-list` | display a list of available Large Language Models and exit |
|
|
133
135
|
| `--llm-compare` | compare the generated messages from all models - but do not commit |
|
|
134
136
|
| `--llm-model MODEL` | choose the LLM model by name (the default is normally best) |
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnowennixon/diffdash",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "A command-line tool to generate Git commit messages using AI",
|
|
5
5
|
"license": "0BSD",
|
|
6
6
|
"author": "John Owen Nixon",
|
|
@@ -42,19 +42,19 @@
|
|
|
42
42
|
"test": "run-s -ls lint build"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@ai-sdk/anthropic": "3.0.
|
|
46
|
-
"@ai-sdk/deepseek": "2.0.
|
|
47
|
-
"@ai-sdk/google": "3.0.
|
|
48
|
-
"@ai-sdk/openai": "3.0.
|
|
49
|
-
"@inquirer/prompts": "8.2.
|
|
50
|
-
"@openrouter/ai-sdk-provider": "2.
|
|
51
|
-
"ai": "6.0.
|
|
45
|
+
"@ai-sdk/anthropic": "3.0.44",
|
|
46
|
+
"@ai-sdk/deepseek": "2.0.20",
|
|
47
|
+
"@ai-sdk/google": "3.0.29",
|
|
48
|
+
"@ai-sdk/openai": "3.0.29",
|
|
49
|
+
"@inquirer/prompts": "8.2.1",
|
|
50
|
+
"@openrouter/ai-sdk-provider": "2.2.3",
|
|
51
|
+
"ai": "6.0.86",
|
|
52
52
|
"ansis": "4.2.0",
|
|
53
53
|
"argparse": "2.0.1",
|
|
54
54
|
"cli-table3": "0.6.5",
|
|
55
55
|
"json5": "2.2.3",
|
|
56
56
|
"magic-regexp": "0.10.0",
|
|
57
|
-
"simple-git": "3.
|
|
57
|
+
"simple-git": "3.31.1",
|
|
58
58
|
"zod": "4.3.6"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
@@ -63,12 +63,12 @@
|
|
|
63
63
|
"@johnowennixon/add-shebangs": "1.1.0",
|
|
64
64
|
"@johnowennixon/chmodx": "2.1.0",
|
|
65
65
|
"@types/argparse": "2.0.17",
|
|
66
|
-
"@types/node": "25.
|
|
66
|
+
"@types/node": "25.2.3",
|
|
67
67
|
"@typescript/native-preview": "7.0.0-dev.20260103.1",
|
|
68
|
-
"knip": "5.
|
|
68
|
+
"knip": "5.83.1",
|
|
69
69
|
"markdownlint-cli2": "0.20.0",
|
|
70
70
|
"npm-run-all2": "8.0.4",
|
|
71
|
-
"oxlint": "1.
|
|
71
|
+
"oxlint": "1.47.0",
|
|
72
72
|
"rimraf": "6.1.2",
|
|
73
73
|
"typescript": "5.9.3"
|
|
74
74
|
}
|
package/dist/src/lib_ansi.js
CHANGED
package/dist/src/lib_cli.js
CHANGED
|
@@ -1,33 +1,70 @@
|
|
|
1
1
|
import { ArgumentParser } from "argparse";
|
|
2
2
|
import { EMPTY } from "./lib_char_empty.js";
|
|
3
|
-
import { DASH, PLUS, UNDERSCORE } from "./lib_char_punctuation.js";
|
|
3
|
+
import { DASH, PLUS, QUESTION, UNDERSCORE } from "./lib_char_punctuation.js";
|
|
4
4
|
import { debug_channels, debug_inspect_when } from "./lib_debug.js";
|
|
5
|
-
export function
|
|
5
|
+
export function cli_string_optional(params) {
|
|
6
|
+
const { help, metavar } = params;
|
|
7
|
+
const options = { help, metavar };
|
|
6
8
|
return { kind: "string", options, value: "" };
|
|
7
9
|
}
|
|
8
|
-
export function
|
|
10
|
+
export function cli_string_required(params) {
|
|
11
|
+
const { help, metavar } = params;
|
|
12
|
+
const options = { help, metavar, required: true };
|
|
9
13
|
return { kind: "string", options, value: "" };
|
|
10
14
|
}
|
|
11
|
-
export function
|
|
15
|
+
export function cli_string_default(params) {
|
|
16
|
+
const { help, metavar, default: _default } = params;
|
|
17
|
+
const options = { help, metavar, default: _default };
|
|
18
|
+
return { kind: "string", options, value: "" };
|
|
19
|
+
}
|
|
20
|
+
export function cli_string_positional_required(params) {
|
|
21
|
+
const { help, metavar } = params;
|
|
22
|
+
const options = { help, metavar, positional: true };
|
|
23
|
+
return { kind: "string", options, value: "" };
|
|
24
|
+
}
|
|
25
|
+
export function cli_string_positional_optional(params) {
|
|
26
|
+
const { help, metavar } = params;
|
|
27
|
+
const options = { help, metavar, positional: true, nargs: QUESTION };
|
|
28
|
+
return { kind: "string", options, value: "" };
|
|
29
|
+
}
|
|
30
|
+
export function cli_integer_optional(params) {
|
|
31
|
+
const { help, metavar } = params;
|
|
32
|
+
const options = { help, metavar };
|
|
12
33
|
return { kind: "integer", options, value: 0 };
|
|
13
34
|
}
|
|
14
|
-
export function
|
|
35
|
+
export function cli_integer_default(params) {
|
|
36
|
+
const { help, metavar, default: _default } = params;
|
|
37
|
+
const options = { help, metavar, default: _default };
|
|
15
38
|
return { kind: "integer", options, value: 0 };
|
|
16
39
|
}
|
|
17
|
-
export function
|
|
40
|
+
export function cli_boolean_always(params) {
|
|
41
|
+
const { help } = params;
|
|
42
|
+
const options = { help };
|
|
18
43
|
return { kind: "boolean", options, value: false };
|
|
19
44
|
}
|
|
20
|
-
export function
|
|
45
|
+
export function cli_boolean_default(params) {
|
|
46
|
+
const { help, default: _default } = params;
|
|
47
|
+
const options = { help, default: _default };
|
|
48
|
+
return { kind: "boolean", options, value: false };
|
|
49
|
+
}
|
|
50
|
+
export function cli_choice_optional(params) {
|
|
51
|
+
const { help, metavar, choices } = params;
|
|
52
|
+
const options = { help, metavar, choices };
|
|
21
53
|
return { kind: "choice", options, value: undefined };
|
|
22
54
|
}
|
|
23
|
-
export function
|
|
55
|
+
export function cli_choice_required(params) {
|
|
56
|
+
const { help, metavar, choices } = params;
|
|
57
|
+
const options = { help, metavar, choices, required: true };
|
|
24
58
|
return { kind: "choice", options, value: undefined };
|
|
25
59
|
}
|
|
26
|
-
export function
|
|
27
|
-
|
|
60
|
+
export function cli_choice_default(params) {
|
|
61
|
+
const { help, metavar, choices, default: _default } = params;
|
|
62
|
+
const options = { help, metavar, choices, default: _default };
|
|
28
63
|
return { kind: "choice", options, value: undefined };
|
|
29
64
|
}
|
|
30
|
-
export function
|
|
65
|
+
export function cli_list_positional(params) {
|
|
66
|
+
const { help } = params;
|
|
67
|
+
const options = { help, positional: true };
|
|
31
68
|
return { kind: "list", options, value: [] };
|
|
32
69
|
}
|
|
33
70
|
export function cli_meg_optional(meg_schema) {
|
|
@@ -36,14 +73,11 @@ export function cli_meg_optional(meg_schema) {
|
|
|
36
73
|
export function cli_meg_required(meg_schema) {
|
|
37
74
|
return { kind: "meg", options: { required: true }, value: meg_schema };
|
|
38
75
|
}
|
|
39
|
-
export function cli_meg_required_predicate(meg_schema, predicate) {
|
|
40
|
-
return { kind: "meg", options: { required: true, predicate }, value: meg_schema };
|
|
41
|
-
}
|
|
42
76
|
function cli_omit(obj, key_to_omit) {
|
|
43
77
|
const { [key_to_omit]: _, ...rest } = obj;
|
|
44
78
|
return rest;
|
|
45
79
|
}
|
|
46
|
-
function cli_add_keys({ cli_schema, parser_group
|
|
80
|
+
function cli_add_keys({ cli_schema, parser_group }) {
|
|
47
81
|
for (const key in cli_schema) {
|
|
48
82
|
if (!Object.hasOwn(cli_schema, key)) {
|
|
49
83
|
continue;
|
|
@@ -52,11 +86,6 @@ function cli_add_keys({ cli_schema, parser_group, predicate, }) {
|
|
|
52
86
|
if (!cli) {
|
|
53
87
|
continue;
|
|
54
88
|
}
|
|
55
|
-
if (predicate !== undefined) {
|
|
56
|
-
if (!predicate(key)) {
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
89
|
const key_replaced = key.replaceAll(UNDERSCORE, DASH);
|
|
61
90
|
const key_amended = `${cli.options.positional === true ? EMPTY : "--"}${key_replaced}`;
|
|
62
91
|
const options = cli_omit(cli.options, "positional");
|
|
@@ -82,7 +111,6 @@ function cli_add_keys({ cli_schema, parser_group, predicate, }) {
|
|
|
82
111
|
cli_add_keys({
|
|
83
112
|
cli_schema: cli.value,
|
|
84
113
|
parser_group: mutually_exclusive_group,
|
|
85
|
-
predicate: cli.options.predicate,
|
|
86
114
|
});
|
|
87
115
|
}
|
|
88
116
|
break;
|
|
@@ -91,7 +119,7 @@ function cli_add_keys({ cli_schema, parser_group, predicate, }) {
|
|
|
91
119
|
}
|
|
92
120
|
}
|
|
93
121
|
}
|
|
94
|
-
function cli_recursive_parse({ schema, namespace,
|
|
122
|
+
function cli_recursive_parse({ schema, namespace, }) {
|
|
95
123
|
const result = {};
|
|
96
124
|
for (const key in schema) {
|
|
97
125
|
if (!Object.hasOwn(schema, key)) {
|
|
@@ -101,17 +129,11 @@ function cli_recursive_parse({ schema, namespace, predicate, }) {
|
|
|
101
129
|
if (!cli) {
|
|
102
130
|
continue;
|
|
103
131
|
}
|
|
104
|
-
if (predicate !== undefined) {
|
|
105
|
-
if (!predicate(key)) {
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
132
|
if (cli.kind === "meg") {
|
|
110
133
|
const nested_schema = cli.value;
|
|
111
134
|
result[key] = cli_recursive_parse({
|
|
112
135
|
schema: nested_schema,
|
|
113
136
|
namespace,
|
|
114
|
-
predicate: cli.options.predicate,
|
|
115
137
|
});
|
|
116
138
|
}
|
|
117
139
|
else {
|
package/dist/src/lib_debug.js
CHANGED
|
@@ -4,6 +4,7 @@ import { enabled_from_env } from "./lib_enabled.js";
|
|
|
4
4
|
import { inspect_obj_to_string } from "./lib_inspect.js";
|
|
5
5
|
import { stdio_write_stderr_linefeed } from "./lib_stdio_write.js";
|
|
6
6
|
import { tell_debug } from "./lib_tell.js";
|
|
7
|
+
import { tui_quote_smart_single as qss } from "./lib_tui_quote.js";
|
|
7
8
|
export const debug_channels = {
|
|
8
9
|
api: false,
|
|
9
10
|
backups: false,
|
|
@@ -37,7 +38,7 @@ export const debug_channels = {
|
|
|
37
38
|
export function debug_enable_if(channel, enabled) {
|
|
38
39
|
if (enabled && !debug_channels[channel]) {
|
|
39
40
|
debug_channels[channel] = true;
|
|
40
|
-
tell_debug(`Debugging enabled for
|
|
41
|
+
tell_debug(`Debugging enabled for ${qss(channel)}`);
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
function debug_init() {
|
|
@@ -1,33 +1,40 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cli_boolean_always, cli_choice_default, cli_make_parser, cli_string_optional } from "./lib_cli.js";
|
|
2
2
|
import { diffdash_llm_model_choices, diffdash_llm_model_default } from "./lib_diffdash_llm.js";
|
|
3
|
+
import { LANGUAGE_CODE_ENGLISH, language_get_code_choices } from "./lib_language.js";
|
|
4
|
+
import { tui_quote_smart_single as qss } from "./lib_tui_quote.js";
|
|
3
5
|
const diffdash_cli_schema = {
|
|
4
|
-
version:
|
|
5
|
-
auto_add:
|
|
6
|
-
auto_commit:
|
|
7
|
-
auto_push:
|
|
8
|
-
disable_add:
|
|
9
|
-
disable_status:
|
|
10
|
-
disable_preview:
|
|
11
|
-
disable_commit:
|
|
12
|
-
disable_push:
|
|
13
|
-
add_prefix:
|
|
14
|
-
add_suffix:
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
version: cli_boolean_always({ help: "show program version information and exit" }),
|
|
7
|
+
auto_add: cli_boolean_always({ help: "automatically stage all changes without confirmation" }),
|
|
8
|
+
auto_commit: cli_boolean_always({ help: "automatically commit changes without confirmation" }),
|
|
9
|
+
auto_push: cli_boolean_always({ help: "automatically push changes after commit without confirmation" }),
|
|
10
|
+
disable_add: cli_boolean_always({ help: "disable adding unstaged changes - exit if no changes staged" }),
|
|
11
|
+
disable_status: cli_boolean_always({ help: "disable listing the staged files before generating a message" }),
|
|
12
|
+
disable_preview: cli_boolean_always({ help: "disable previewing the generated message" }),
|
|
13
|
+
disable_commit: cli_boolean_always({ help: "disable committing changes - exit after generating the message" }),
|
|
14
|
+
disable_push: cli_boolean_always({ help: "disable pushing changes - exit after making the commit" }),
|
|
15
|
+
add_prefix: cli_string_optional({ help: "add a prefix to the commit message summary line", metavar: "PREFIX" }),
|
|
16
|
+
add_suffix: cli_string_optional({ help: "add a suffix to the commit message summary line", metavar: "SUFFIX" }),
|
|
17
|
+
language: cli_choice_default({
|
|
18
|
+
help: `choose the language for commit messages (defaults to ${qss(LANGUAGE_CODE_ENGLISH)})`,
|
|
19
|
+
choices: language_get_code_choices(),
|
|
20
|
+
default: LANGUAGE_CODE_ENGLISH,
|
|
21
|
+
}),
|
|
22
|
+
llm_list: cli_boolean_always({ help: "display a list of available Large Language Models and exit" }),
|
|
23
|
+
llm_compare: cli_boolean_always({ help: "compare the generated messages from all models - but do not commit" }),
|
|
17
24
|
llm_model: cli_choice_default({
|
|
18
|
-
help: `choose the Large Language Model by name (defaults to ${diffdash_llm_model_default})`,
|
|
25
|
+
help: `choose the Large Language Model by name (defaults to ${qss(diffdash_llm_model_default)})`,
|
|
19
26
|
choices: diffdash_llm_model_choices,
|
|
20
27
|
default: diffdash_llm_model_default,
|
|
21
28
|
}),
|
|
22
|
-
llm_excludes:
|
|
23
|
-
no_secret_check:
|
|
24
|
-
no_verify:
|
|
25
|
-
force:
|
|
26
|
-
just_output:
|
|
27
|
-
silent:
|
|
28
|
-
debug_llm_prompts:
|
|
29
|
-
debug_llm_inputs:
|
|
30
|
-
debug_llm_outputs:
|
|
29
|
+
llm_excludes: cli_string_optional({ help: "models to exclude from comparison (comma separated)", metavar: "MODELS" }),
|
|
30
|
+
no_secret_check: cli_boolean_always({ help: "bypass checking for secrets in diffs" }),
|
|
31
|
+
no_verify: cli_boolean_always({ help: "bypass git hooks when committing or pushing to Git" }),
|
|
32
|
+
force: cli_boolean_always({ help: "apply force when pushing to Git" }),
|
|
33
|
+
just_output: cli_boolean_always({ help: "just output the commit message for use in scripts" }),
|
|
34
|
+
silent: cli_boolean_always({ help: "suppress all normal output - errors and aborts still display" }),
|
|
35
|
+
debug_llm_prompts: cli_boolean_always({ help: "debug prompts sent to the LLM" }),
|
|
36
|
+
debug_llm_inputs: cli_boolean_always({ help: "debug inputs object sent to the LLM" }),
|
|
37
|
+
debug_llm_outputs: cli_boolean_always({ help: "debug outputs object received from the LLM" }),
|
|
31
38
|
};
|
|
32
39
|
export const diffdash_cli_parser = cli_make_parser({
|
|
33
40
|
cli_schema: diffdash_cli_schema,
|
|
@@ -6,11 +6,12 @@ import { diffdash_llm_model_details } from "./lib_diffdash_llm.js";
|
|
|
6
6
|
import { file_io_read_text } from "./lib_file_io.js";
|
|
7
7
|
import { file_is_file } from "./lib_file_is.js";
|
|
8
8
|
import { json5_parse } from "./lib_json5.js";
|
|
9
|
+
import { language_get_name_from_code } from "./lib_language.js";
|
|
9
10
|
import { llm_config_get, llm_config_get_all } from "./lib_llm_config.js";
|
|
10
11
|
import { llm_list_models } from "./lib_llm_list.js";
|
|
11
12
|
import { PACKAGE_NAME, PACKAGE_VERSION } from "./lib_package.js";
|
|
12
13
|
import { tell_plain } from "./lib_tell.js";
|
|
13
|
-
import { tui_quote_smart_single } from "./lib_tui_quote.js";
|
|
14
|
+
import { tui_quote_smart_single as qss } from "./lib_tui_quote.js";
|
|
14
15
|
const diffdash_config_file_schema = z
|
|
15
16
|
.object({
|
|
16
17
|
extra_prompts: z.string().array().optional(),
|
|
@@ -25,7 +26,7 @@ function diffdash_config_file_read(config) {
|
|
|
25
26
|
const parsed_json = json5_parse(config_content);
|
|
26
27
|
const validation_result = diffdash_config_file_schema.safeParse(parsed_json);
|
|
27
28
|
if (!validation_result.success) {
|
|
28
|
-
abort_with_error(`Unable to parse DiffDash config file: ${
|
|
29
|
+
abort_with_error(`Unable to parse DiffDash config file: ${qss(config_file_name)}`);
|
|
29
30
|
}
|
|
30
31
|
const data = validation_result.data;
|
|
31
32
|
if (data.extra_prompts) {
|
|
@@ -33,7 +34,7 @@ function diffdash_config_file_read(config) {
|
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
export function diffdash_config_get() {
|
|
36
|
-
const { version, auto_add, auto_commit, auto_push, disable_add, disable_commit, disable_preview, disable_status, disable_push, add_prefix, add_suffix, llm_list, llm_compare, llm_model, llm_excludes, no_secret_check, no_verify, force, just_output, silent, debug_llm_prompts, debug_llm_inputs, debug_llm_outputs, } = diffdash_cli_parsed_args;
|
|
37
|
+
const { version, auto_add, auto_commit, auto_push, disable_add, disable_commit, disable_preview, disable_status, disable_push, add_prefix, add_suffix, language, llm_list, llm_compare, llm_model, llm_excludes, no_secret_check, no_verify, force, just_output, silent, debug_llm_prompts, debug_llm_inputs, debug_llm_outputs, } = diffdash_cli_parsed_args;
|
|
37
38
|
if (version) {
|
|
38
39
|
tell_plain(`${PACKAGE_NAME} v${PACKAGE_VERSION}`);
|
|
39
40
|
process.exit(0);
|
|
@@ -42,6 +43,7 @@ export function diffdash_config_get() {
|
|
|
42
43
|
llm_list_models({ llm_model_details: diffdash_llm_model_details });
|
|
43
44
|
process.exit(0);
|
|
44
45
|
}
|
|
46
|
+
const language_name = language_get_name_from_code(language);
|
|
45
47
|
const llm_config = llm_config_get({ llm_model_details: diffdash_llm_model_details, llm_model_name: llm_model });
|
|
46
48
|
const all_llm_configs = llm_config_get_all({ llm_model_details: diffdash_llm_model_details, llm_excludes });
|
|
47
49
|
debug_channels.llm_prompts = debug_llm_prompts;
|
|
@@ -58,6 +60,7 @@ export function diffdash_config_get() {
|
|
|
58
60
|
disable_push,
|
|
59
61
|
add_prefix,
|
|
60
62
|
add_suffix,
|
|
63
|
+
language_name,
|
|
61
64
|
no_secret_check,
|
|
62
65
|
no_verify,
|
|
63
66
|
force,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { env_get_substitute } from "./lib_env.js";
|
|
2
2
|
import { llm_model_get_choices, llm_model_get_details } from "./lib_llm_model.js";
|
|
3
|
-
const model_name_default = "gpt-
|
|
3
|
+
const model_name_default = "gpt-5-mini-minimal";
|
|
4
4
|
const model_name_options = [
|
|
5
|
-
"claude-
|
|
5
|
+
"claude-haiku-4.5", // fallback
|
|
6
6
|
"deepseek-chat",
|
|
7
7
|
"gemini-2.5-flash",
|
|
8
8
|
"gemini-3-flash-preview-low",
|
|
9
|
-
"gpt-4.1-mini", //
|
|
9
|
+
"gpt-4.1-mini", // fallback
|
|
10
10
|
"gpt-4.1-nano",
|
|
11
11
|
"gpt-5-mini",
|
|
12
|
-
"gpt-5-mini-minimal", //
|
|
12
|
+
"gpt-5-mini-minimal", // the best
|
|
13
13
|
"gpt-5-nano",
|
|
14
14
|
"gpt-5-nano-minimal",
|
|
15
15
|
"grok-code-fast-1",
|
|
@@ -93,7 +93,7 @@ async function phase_status({ config, git }) {
|
|
|
93
93
|
}
|
|
94
94
|
async function phase_compare({ config, git }) {
|
|
95
95
|
const { silent } = config;
|
|
96
|
-
const { all_llm_configs, add_prefix, add_suffix, no_secret_check, extra_prompts } = config;
|
|
96
|
+
const { all_llm_configs, add_prefix, add_suffix, no_secret_check, extra_prompts, language_name } = config;
|
|
97
97
|
const diffstat = await git_simple_staging_get_staged_diffstat(git);
|
|
98
98
|
const diff = await git_simple_staging_get_staged_diff(git);
|
|
99
99
|
if (!no_secret_check) {
|
|
@@ -104,7 +104,7 @@ async function phase_compare({ config, git }) {
|
|
|
104
104
|
abort_with_error(`Aborting: ${error_get_message(error)}`);
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
-
const inputs = { diffstat, diff, extra_prompts };
|
|
107
|
+
const inputs = { diffstat, diff, extra_prompts, language_name };
|
|
108
108
|
if (!silent) {
|
|
109
109
|
tell_action("Generating Git commit messages using all models in parallel");
|
|
110
110
|
}
|
|
@@ -129,7 +129,7 @@ async function phase_compare({ config, git }) {
|
|
|
129
129
|
llm_results_summary(all_results);
|
|
130
130
|
}
|
|
131
131
|
async function phase_generate({ config, git }) {
|
|
132
|
-
const { disable_preview, add_prefix, add_suffix, llm_config, no_secret_check, just_output, silent, extra_prompts } = config;
|
|
132
|
+
const { disable_preview, add_prefix, add_suffix, llm_config, no_secret_check, just_output, silent, extra_prompts, language_name, } = config;
|
|
133
133
|
const { llm_model_name } = llm_config;
|
|
134
134
|
const diffstat = await git_simple_staging_get_staged_diffstat(git);
|
|
135
135
|
const diff = await git_simple_staging_get_staged_diff(git);
|
|
@@ -141,7 +141,7 @@ async function phase_generate({ config, git }) {
|
|
|
141
141
|
abort_with_error(`Aborting: ${error_get_message(error)}`);
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
|
-
const inputs = { diffstat, diff, extra_prompts };
|
|
144
|
+
const inputs = { diffstat, diff, extra_prompts, language_name };
|
|
145
145
|
if (!silent && !just_output) {
|
|
146
146
|
tell_action(`Generating the Git commit message using ${llm_model_name}`);
|
|
147
147
|
}
|
|
@@ -2,10 +2,12 @@ import { LF } from "./lib_char_control.js";
|
|
|
2
2
|
import { EMPTY } from "./lib_char_empty.js";
|
|
3
3
|
import { tell_warning } from "./lib_tell.js";
|
|
4
4
|
const LF_LF = LF + LF;
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
function portion_role(language_name) {
|
|
6
|
+
return (`
|
|
7
|
+
Your role is to generate a Git commit message in conversational ${language_name}.
|
|
7
8
|
The user does not want Conventional Commits - the summary line must be a normal sentence.
|
|
8
|
-
`.trim() + LF_LF;
|
|
9
|
+
`.trim() + LF_LF);
|
|
10
|
+
}
|
|
9
11
|
const portion_inputs = `
|
|
10
12
|
The user will send you a <diffstat> block, the output of a 'git diff --staged --stat' command.
|
|
11
13
|
The user will send you a <diff> block, the output of a 'git diff --staged' command.
|
|
@@ -54,7 +56,7 @@ Therefore, you must just output the Git message itself without any introductory
|
|
|
54
56
|
`.trim() + LF_LF;
|
|
55
57
|
export function git_message_prompt_get_system({ has_structured_json, inputs, }) {
|
|
56
58
|
let system_prompt = EMPTY;
|
|
57
|
-
system_prompt += portion_role;
|
|
59
|
+
system_prompt += portion_role(inputs.language_name);
|
|
58
60
|
system_prompt += portion_inputs;
|
|
59
61
|
system_prompt += portion_reminders;
|
|
60
62
|
system_prompt += portion_format(has_structured_json);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { abort_with_error } from "./lib_abort.js";
|
|
2
|
+
import { tui_quote_smart_single as qss } from "./lib_tui_quote.js";
|
|
3
|
+
export const LANGUAGE_CODE_ENGLISH = "en";
|
|
4
|
+
export const LANGUAGE_DETAILS = [
|
|
5
|
+
{ code: "af", name: "Afrikaans" },
|
|
6
|
+
{ code: "bg", name: "Bulgarian" },
|
|
7
|
+
{ code: "bn", name: "Bengali" },
|
|
8
|
+
{ code: "ca", name: "Catalan" },
|
|
9
|
+
{ code: "cs", name: "Czech" },
|
|
10
|
+
{ code: "da", name: "Danish" },
|
|
11
|
+
{ code: "de", name: "German" },
|
|
12
|
+
{ code: "el", name: "Greek" },
|
|
13
|
+
{ code: "en", name: "English" },
|
|
14
|
+
{ code: "es", name: "Spanish" },
|
|
15
|
+
{ code: "et", name: "Estonian" },
|
|
16
|
+
{ code: "fi", name: "Finnish" },
|
|
17
|
+
{ code: "fr", name: "French" },
|
|
18
|
+
{ code: "hi", name: "Hindi" },
|
|
19
|
+
{ code: "hr", name: "Croatian" },
|
|
20
|
+
{ code: "hu", name: "Hungarian" },
|
|
21
|
+
{ code: "id", name: "Indonesian" },
|
|
22
|
+
{ code: "it", name: "Italian" },
|
|
23
|
+
{ code: "ja", name: "Japanese" },
|
|
24
|
+
{ code: "ko", name: "Korean" },
|
|
25
|
+
{ code: "lt", name: "Lithuanian" },
|
|
26
|
+
{ code: "lv", name: "Latvian" },
|
|
27
|
+
{ code: "ms", name: "Malay" },
|
|
28
|
+
{ code: "nl", name: "Dutch" },
|
|
29
|
+
{ code: "no", name: "Norwegian" },
|
|
30
|
+
{ code: "pl", name: "Polish" },
|
|
31
|
+
{ code: "pt", name: "Portuguese" },
|
|
32
|
+
{ code: "ro", name: "Romanian" },
|
|
33
|
+
{ code: "ru", name: "Russian" },
|
|
34
|
+
{ code: "sk", name: "Slovak" },
|
|
35
|
+
{ code: "sl", name: "Slovenian" },
|
|
36
|
+
{ code: "sr", name: "Serbian" },
|
|
37
|
+
{ code: "sv", name: "Swedish" },
|
|
38
|
+
{ code: "sw", name: "Swahili" },
|
|
39
|
+
{ code: "ta", name: "Tamil" },
|
|
40
|
+
{ code: "te", name: "Telugu" },
|
|
41
|
+
{ code: "th", name: "Thai" },
|
|
42
|
+
{ code: "tr", name: "Turkish" },
|
|
43
|
+
{ code: "uk", name: "Ukrainian" },
|
|
44
|
+
{ code: "vi", name: "Vietnamese" },
|
|
45
|
+
{ code: "zh-CN", name: "Chinese (Simplified)" },
|
|
46
|
+
{ code: "zh-HK", name: "Chinese (Traditional)" },
|
|
47
|
+
{ code: "zh-SG", name: "Chinese (Simplified)" },
|
|
48
|
+
{ code: "zh-TW", name: "Chinese (Traditional)" },
|
|
49
|
+
];
|
|
50
|
+
export function language_get_code_choices() {
|
|
51
|
+
return LANGUAGE_DETAILS.map((language) => language.code);
|
|
52
|
+
}
|
|
53
|
+
export function language_get_name_from_code(code) {
|
|
54
|
+
const language_entry = LANGUAGE_DETAILS.find((language) => language.code === code);
|
|
55
|
+
if (!language_entry) {
|
|
56
|
+
abort_with_error(`Unknown language code: ${qss(code)}`);
|
|
57
|
+
}
|
|
58
|
+
return language_entry.name;
|
|
59
|
+
}
|
|
@@ -31,84 +31,78 @@ function provider_options_openai({ reasoning_effort, }) {
|
|
|
31
31
|
},
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
-
function provider_options_openrouter({ only }) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
function provider_options_openrouter({ only, thinking, }) {
|
|
35
|
+
if (only !== undefined && thinking !== undefined) {
|
|
36
|
+
return {
|
|
37
|
+
openrouter: {
|
|
38
|
+
provider: {
|
|
39
|
+
only: [only],
|
|
40
|
+
},
|
|
41
|
+
thinking,
|
|
39
42
|
},
|
|
40
|
-
}
|
|
41
|
-
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (thinking !== undefined) {
|
|
46
|
+
return {
|
|
47
|
+
openrouter: {
|
|
48
|
+
thinking,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (only !== undefined) {
|
|
53
|
+
return {
|
|
54
|
+
openrouter: {
|
|
55
|
+
provider: {
|
|
56
|
+
only: [only],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
42
62
|
}
|
|
43
63
|
export const LLM_MODEL_DETAILS = [
|
|
44
64
|
{
|
|
45
|
-
llm_model_name: "claude-
|
|
46
|
-
llm_model_code: "claude-
|
|
47
|
-
llm_api_code: "anthropic",
|
|
48
|
-
context_window: 200_000,
|
|
49
|
-
max_output_tokens: 8192,
|
|
50
|
-
cents_input: 80,
|
|
51
|
-
cents_output: 400,
|
|
52
|
-
default_reasoning: false,
|
|
53
|
-
has_structured_json: true,
|
|
54
|
-
recommended_temperature: undefined,
|
|
55
|
-
provider_options: provider_options_anthropic({ thinking: false }),
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
llm_model_name: "claude-opus-4.5",
|
|
59
|
-
llm_model_code: "claude-opus-4-5",
|
|
65
|
+
llm_model_name: "claude-haiku-4.5",
|
|
66
|
+
llm_model_code: "claude-haiku-4-5",
|
|
60
67
|
llm_api_code: "anthropic",
|
|
61
68
|
context_window: 200_000,
|
|
62
69
|
max_output_tokens: 64_000,
|
|
63
|
-
cents_input:
|
|
64
|
-
cents_output:
|
|
70
|
+
cents_input: 100,
|
|
71
|
+
cents_output: 500,
|
|
65
72
|
default_reasoning: false,
|
|
66
73
|
has_structured_json: true,
|
|
67
74
|
recommended_temperature: undefined,
|
|
68
75
|
provider_options: provider_options_anthropic({ thinking: false }),
|
|
69
76
|
},
|
|
70
77
|
{
|
|
71
|
-
llm_model_name: "claude-opus-4.
|
|
72
|
-
llm_model_code: "claude-opus-4-
|
|
73
|
-
llm_api_code: "anthropic",
|
|
74
|
-
context_window: 200_000,
|
|
75
|
-
max_output_tokens: 64_000 - 1024,
|
|
76
|
-
cents_input: 300, // for input tokens <= 200K
|
|
77
|
-
cents_output: 1500, // for input tokens <= 200K
|
|
78
|
-
default_reasoning: false,
|
|
79
|
-
has_structured_json: true,
|
|
80
|
-
recommended_temperature: undefined,
|
|
81
|
-
provider_options: provider_options_anthropic({ thinking: true }),
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
llm_model_name: "claude-sonnet-4",
|
|
85
|
-
llm_model_code: "claude-sonnet-4-0",
|
|
78
|
+
llm_model_name: "claude-opus-4.6",
|
|
79
|
+
llm_model_code: "claude-opus-4-6",
|
|
86
80
|
llm_api_code: "anthropic",
|
|
87
|
-
context_window: 200_000,
|
|
88
|
-
max_output_tokens:
|
|
89
|
-
cents_input:
|
|
90
|
-
cents_output:
|
|
81
|
+
context_window: 200_000, // 1_000_000 available with context-1m beta header
|
|
82
|
+
max_output_tokens: 128_000,
|
|
83
|
+
cents_input: 500, // for input tokens <= 200K
|
|
84
|
+
cents_output: 2500, // for input tokens <= 200K
|
|
91
85
|
default_reasoning: false,
|
|
92
86
|
has_structured_json: true,
|
|
93
87
|
recommended_temperature: undefined,
|
|
94
88
|
provider_options: provider_options_anthropic({ thinking: false }),
|
|
95
89
|
},
|
|
96
90
|
{
|
|
97
|
-
llm_model_name: "claude-
|
|
98
|
-
llm_model_code: "claude-
|
|
91
|
+
llm_model_name: "claude-opus-4.6-thinking",
|
|
92
|
+
llm_model_code: "claude-opus-4-6",
|
|
99
93
|
llm_api_code: "anthropic",
|
|
100
|
-
context_window: 200_000,
|
|
101
|
-
max_output_tokens:
|
|
102
|
-
cents_input:
|
|
103
|
-
cents_output:
|
|
94
|
+
context_window: 200_000, // 1_000_000 available with context-1m beta header
|
|
95
|
+
max_output_tokens: 128_000 - 1024,
|
|
96
|
+
cents_input: 500, // for input tokens <= 200K
|
|
97
|
+
cents_output: 2500, // for input tokens <= 200K
|
|
104
98
|
default_reasoning: true,
|
|
105
99
|
has_structured_json: true,
|
|
106
100
|
recommended_temperature: undefined,
|
|
107
101
|
provider_options: provider_options_anthropic({ thinking: true }),
|
|
108
102
|
},
|
|
109
103
|
{
|
|
110
|
-
llm_model_name: "claude-sonnet-4.
|
|
111
|
-
llm_model_code: "claude-sonnet-4-
|
|
104
|
+
llm_model_name: "claude-sonnet-4.6",
|
|
105
|
+
llm_model_code: "claude-sonnet-4-6",
|
|
112
106
|
llm_api_code: "anthropic",
|
|
113
107
|
context_window: 200_000, // 1_000_000 available with context-1m beta header
|
|
114
108
|
max_output_tokens: 64_000,
|
|
@@ -120,14 +114,14 @@ export const LLM_MODEL_DETAILS = [
|
|
|
120
114
|
provider_options: provider_options_anthropic({ thinking: false }),
|
|
121
115
|
},
|
|
122
116
|
{
|
|
123
|
-
llm_model_name: "claude-sonnet-4.
|
|
124
|
-
llm_model_code: "claude-sonnet-4-
|
|
117
|
+
llm_model_name: "claude-sonnet-4.6-thinking",
|
|
118
|
+
llm_model_code: "claude-sonnet-4-6",
|
|
125
119
|
llm_api_code: "anthropic",
|
|
126
120
|
context_window: 200_000, // 1_000_000 available with context-1m beta header
|
|
127
121
|
max_output_tokens: 62_976, // = 64000 - 1024 used for reasoning
|
|
128
122
|
cents_input: 300, // for input tokens <= 200K
|
|
129
123
|
cents_output: 1500, // for input tokens <= 200K
|
|
130
|
-
default_reasoning:
|
|
124
|
+
default_reasoning: true,
|
|
131
125
|
has_structured_json: true,
|
|
132
126
|
recommended_temperature: undefined,
|
|
133
127
|
provider_options: provider_options_anthropic({ thinking: true }),
|
|
@@ -257,7 +251,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
257
251
|
max_output_tokens: 65_536,
|
|
258
252
|
cents_input: 200,
|
|
259
253
|
cents_output: 1200,
|
|
260
|
-
default_reasoning:
|
|
254
|
+
default_reasoning: true,
|
|
261
255
|
has_structured_json: true,
|
|
262
256
|
recommended_temperature: undefined,
|
|
263
257
|
provider_options: provider_options_google({ thinking_level: "low" }),
|
|
@@ -275,6 +269,19 @@ export const LLM_MODEL_DETAILS = [
|
|
|
275
269
|
recommended_temperature: undefined,
|
|
276
270
|
provider_options: provider_options_openrouter({ only: "z-ai" }),
|
|
277
271
|
},
|
|
272
|
+
{
|
|
273
|
+
llm_model_name: "glm-4.7-flash@z-ai",
|
|
274
|
+
llm_model_code: "z-ai/glm-4.7-flash",
|
|
275
|
+
llm_api_code: "openrouter",
|
|
276
|
+
context_window: 200_000,
|
|
277
|
+
max_output_tokens: 131_072,
|
|
278
|
+
cents_input: 7,
|
|
279
|
+
cents_output: 40,
|
|
280
|
+
default_reasoning: true,
|
|
281
|
+
has_structured_json: false,
|
|
282
|
+
recommended_temperature: undefined,
|
|
283
|
+
provider_options: provider_options_openrouter({ only: "z-ai" }),
|
|
284
|
+
},
|
|
278
285
|
{
|
|
279
286
|
llm_model_name: "gpt-4.1",
|
|
280
287
|
llm_model_code: "gpt-4.1",
|
|
@@ -523,30 +530,43 @@ export const LLM_MODEL_DETAILS = [
|
|
|
523
530
|
provider_options: undefined,
|
|
524
531
|
},
|
|
525
532
|
{
|
|
526
|
-
llm_model_name: "kimi-k2
|
|
527
|
-
llm_model_code: "moonshotai/kimi-k2",
|
|
533
|
+
llm_model_name: "kimi-k2.5@moonshot",
|
|
534
|
+
llm_model_code: "moonshotai/kimi-k2.5",
|
|
528
535
|
llm_api_code: "openrouter",
|
|
529
536
|
context_window: 131_072,
|
|
530
537
|
max_output_tokens: 131_072,
|
|
531
538
|
cents_input: 60,
|
|
532
|
-
cents_output:
|
|
533
|
-
default_reasoning:
|
|
539
|
+
cents_output: 300,
|
|
540
|
+
default_reasoning: true,
|
|
534
541
|
has_structured_json: true,
|
|
535
542
|
recommended_temperature: undefined,
|
|
536
543
|
provider_options: provider_options_openrouter({ only: "moonshotai" }),
|
|
537
544
|
},
|
|
538
545
|
{
|
|
539
|
-
llm_model_name: "kimi-k2
|
|
540
|
-
llm_model_code: "moonshotai/kimi-k2
|
|
546
|
+
llm_model_name: "kimi-k2.5@groq",
|
|
547
|
+
llm_model_code: "moonshotai/kimi-k2.5",
|
|
541
548
|
llm_api_code: "openrouter",
|
|
542
|
-
context_window:
|
|
543
|
-
max_output_tokens:
|
|
544
|
-
cents_input:
|
|
549
|
+
context_window: 131_072,
|
|
550
|
+
max_output_tokens: 131_072,
|
|
551
|
+
cents_input: 60,
|
|
552
|
+
cents_output: 300,
|
|
553
|
+
default_reasoning: true,
|
|
554
|
+
has_structured_json: true,
|
|
555
|
+
recommended_temperature: undefined,
|
|
556
|
+
provider_options: provider_options_openrouter({ only: "qroq" }),
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
llm_model_name: "kimi-k2.5-nonthinking",
|
|
560
|
+
llm_model_code: "moonshotai/kimi-k2.5",
|
|
561
|
+
llm_api_code: "openrouter",
|
|
562
|
+
context_window: 131_072,
|
|
563
|
+
max_output_tokens: 131_072,
|
|
564
|
+
cents_input: 60,
|
|
545
565
|
cents_output: 300,
|
|
546
566
|
default_reasoning: false,
|
|
547
|
-
has_structured_json:
|
|
567
|
+
has_structured_json: true,
|
|
548
568
|
recommended_temperature: undefined,
|
|
549
|
-
provider_options: provider_options_openrouter({ only: "
|
|
569
|
+
provider_options: provider_options_openrouter({ only: "moonshotai", thinking: false }),
|
|
550
570
|
},
|
|
551
571
|
{
|
|
552
572
|
llm_model_name: "llama-4-maverick@groq",
|
|
@@ -614,8 +634,8 @@ export const LLM_MODEL_DETAILS = [
|
|
|
614
634
|
provider_options: undefined,
|
|
615
635
|
},
|
|
616
636
|
{
|
|
617
|
-
llm_model_name: "minimax-m2.
|
|
618
|
-
llm_model_code: "minimax/minimax-m2.
|
|
637
|
+
llm_model_name: "minimax-m2.5",
|
|
638
|
+
llm_model_code: "minimax/minimax-m2.5",
|
|
619
639
|
llm_api_code: "openrouter",
|
|
620
640
|
context_window: 204_800,
|
|
621
641
|
max_output_tokens: 131_072,
|
|
@@ -3,7 +3,7 @@ import { ansi_yellow } from "./lib_ansi.js";
|
|
|
3
3
|
import { DASH } from "./lib_char_punctuation.js";
|
|
4
4
|
import { text_split_lines } from "./lib_text.js";
|
|
5
5
|
import { tui_confirm } from "./lib_tui_confirm.js";
|
|
6
|
-
import { tui_quote_smart_single } from "./lib_tui_quote.js";
|
|
6
|
+
import { tui_quote_smart_single as qss } from "./lib_tui_quote.js";
|
|
7
7
|
const regexp_word_global = createRegExp(oneOrMore(anyOf(wordChar, exactly(DASH))), [global]);
|
|
8
8
|
const regexp_segment_global = createRegExp(oneOrMore(anyOf(letter, digit)), [global]);
|
|
9
9
|
const regexp_identifier_exactly = createRegExp(anyOf(
|
|
@@ -66,7 +66,7 @@ async function is_secret_segment(segment, not_secret_segments, interactive) {
|
|
|
66
66
|
}
|
|
67
67
|
if (interactive) {
|
|
68
68
|
const confirmed_is_secret = await tui_confirm({
|
|
69
|
-
question: `Is ${
|
|
69
|
+
question: `Is ${qss(segment)} a secret?`,
|
|
70
70
|
default: false,
|
|
71
71
|
style_message: ansi_yellow,
|
|
72
72
|
});
|
|
@@ -82,7 +82,7 @@ export async function secret_check({ text, interactive }) {
|
|
|
82
82
|
const lines = text_split_lines(text);
|
|
83
83
|
for (const line of lines.toReversed()) {
|
|
84
84
|
if (is_secret_line(line)) {
|
|
85
|
-
throw new Error(`Secret detected: ${
|
|
85
|
+
throw new Error(`Secret detected: ${qss(line.trim())}`);
|
|
86
86
|
}
|
|
87
87
|
const words = line.match(regexp_word_global);
|
|
88
88
|
const segments = line.match(regexp_segment_global);
|
|
@@ -97,12 +97,12 @@ export async function secret_check({ text, interactive }) {
|
|
|
97
97
|
}
|
|
98
98
|
for (const word of words) {
|
|
99
99
|
if (is_secret_word(word)) {
|
|
100
|
-
throw new Error(`Secret detected: ${
|
|
100
|
+
throw new Error(`Secret detected: ${qss(word)}`);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
for (const segment of segments) {
|
|
104
104
|
if (await is_secret_segment(segment, not_secret_segments, interactive)) {
|
|
105
|
-
throw new Error(`Secret detected: ${
|
|
105
|
+
throw new Error(`Secret detected: ${qss(segment)}`);
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnowennixon/diffdash",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "A command-line tool to generate Git commit messages using AI",
|
|
5
5
|
"license": "0BSD",
|
|
6
6
|
"author": "John Owen Nixon",
|
|
@@ -42,19 +42,19 @@
|
|
|
42
42
|
"test": "run-s -ls lint build"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@ai-sdk/anthropic": "3.0.
|
|
46
|
-
"@ai-sdk/deepseek": "2.0.
|
|
47
|
-
"@ai-sdk/google": "3.0.
|
|
48
|
-
"@ai-sdk/openai": "3.0.
|
|
49
|
-
"@inquirer/prompts": "8.2.
|
|
50
|
-
"@openrouter/ai-sdk-provider": "2.
|
|
51
|
-
"ai": "6.0.
|
|
45
|
+
"@ai-sdk/anthropic": "3.0.44",
|
|
46
|
+
"@ai-sdk/deepseek": "2.0.20",
|
|
47
|
+
"@ai-sdk/google": "3.0.29",
|
|
48
|
+
"@ai-sdk/openai": "3.0.29",
|
|
49
|
+
"@inquirer/prompts": "8.2.1",
|
|
50
|
+
"@openrouter/ai-sdk-provider": "2.2.3",
|
|
51
|
+
"ai": "6.0.86",
|
|
52
52
|
"ansis": "4.2.0",
|
|
53
53
|
"argparse": "2.0.1",
|
|
54
54
|
"cli-table3": "0.6.5",
|
|
55
55
|
"json5": "2.2.3",
|
|
56
56
|
"magic-regexp": "0.10.0",
|
|
57
|
-
"simple-git": "3.
|
|
57
|
+
"simple-git": "3.31.1",
|
|
58
58
|
"zod": "4.3.6"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
@@ -63,12 +63,12 @@
|
|
|
63
63
|
"@johnowennixon/add-shebangs": "1.1.0",
|
|
64
64
|
"@johnowennixon/chmodx": "2.1.0",
|
|
65
65
|
"@types/argparse": "2.0.17",
|
|
66
|
-
"@types/node": "25.
|
|
66
|
+
"@types/node": "25.2.3",
|
|
67
67
|
"@typescript/native-preview": "7.0.0-dev.20260103.1",
|
|
68
|
-
"knip": "5.
|
|
68
|
+
"knip": "5.83.1",
|
|
69
69
|
"markdownlint-cli2": "0.20.0",
|
|
70
70
|
"npm-run-all2": "8.0.4",
|
|
71
|
-
"oxlint": "1.
|
|
71
|
+
"oxlint": "1.47.0",
|
|
72
72
|
"rimraf": "6.1.2",
|
|
73
73
|
"typescript": "5.9.3"
|
|
74
74
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|