@johnowennixon/diffdash 1.5.0 → 1.6.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 +8 -6
- package/dist/package.json +13 -13
- package/dist/src/lib_datetime.js +2 -10
- package/dist/src/lib_diffdash_llm.js +3 -2
- package/dist/src/lib_error.js +5 -3
- package/dist/src/lib_llm_access.js +13 -13
- package/dist/src/lib_llm_model.js +27 -5
- package/package.json +14 -14
package/README.md
CHANGED
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
A command-line tool to generate Git commit messages using AI.
|
|
4
4
|
|
|
5
|
+
## Demonstration
|
|
6
|
+
|
|
5
7
|

|
|
6
8
|
|
|
7
9
|
## Features
|
|
8
10
|
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Optionally select from a choice of LLM models
|
|
11
|
+
* Generate Git commit messages in natural English
|
|
12
|
+
* Add a footer to the generated commit messages
|
|
13
|
+
* Add a prefix or suffix to the summary line
|
|
14
|
+
* Select from a choice of LLM models
|
|
14
15
|
* Compare messages generated from all configured models
|
|
15
|
-
*
|
|
16
|
+
* Disable or auto-approve various stages
|
|
17
|
+
* Just output the commit message for use in scripts
|
|
16
18
|
* Configuration using standard API provider environment variables
|
|
17
19
|
* Uses the Vercel AI SDK
|
|
18
20
|
* Uses structured JSON with compatible models
|
package/dist/package.json
CHANGED
|
@@ -40,30 +40,30 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@ai-sdk/anthropic": "1.2.12",
|
|
43
|
-
"@ai-sdk/deepseek": "0.2.
|
|
43
|
+
"@ai-sdk/deepseek": "0.2.16",
|
|
44
44
|
"@ai-sdk/google": "1.2.22",
|
|
45
|
-
"@ai-sdk/openai": "1.3.
|
|
45
|
+
"@ai-sdk/openai": "1.3.23",
|
|
46
46
|
"@openrouter/ai-sdk-provider": "0.7.2",
|
|
47
47
|
"@requesty/ai-sdk": "0.0.9",
|
|
48
|
-
"ai": "4.3.
|
|
48
|
+
"ai": "4.3.19",
|
|
49
49
|
"ansis": "4.1.0",
|
|
50
50
|
"argparse": "2.0.1",
|
|
51
51
|
"cli-table3": "0.6.5",
|
|
52
52
|
"simple-git": "3.28.0",
|
|
53
|
-
"zod": "3.25.
|
|
53
|
+
"zod": "3.25.76"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@biomejs/biome": "2.
|
|
56
|
+
"@biomejs/biome": "2.1.1",
|
|
57
57
|
"@eslint/eslintrc": "3.3.1",
|
|
58
|
-
"@eslint/js": "9.
|
|
58
|
+
"@eslint/js": "9.31.0",
|
|
59
59
|
"@johnowennixon/add-shebangs": "1.1.0",
|
|
60
60
|
"@johnowennixon/chmodx": "2.0.0",
|
|
61
|
-
"@stylistic/eslint-plugin": "5.
|
|
61
|
+
"@stylistic/eslint-plugin": "5.2.0",
|
|
62
62
|
"@types/argparse": "2.0.17",
|
|
63
|
-
"@types/node": "24.0.
|
|
64
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
65
|
-
"@typescript-eslint/parser": "8.
|
|
66
|
-
"eslint": "9.
|
|
63
|
+
"@types/node": "24.0.14",
|
|
64
|
+
"@typescript-eslint/eslint-plugin": "8.37.0",
|
|
65
|
+
"@typescript-eslint/parser": "8.37.0",
|
|
66
|
+
"eslint": "9.31.0",
|
|
67
67
|
"eslint-import-resolver-typescript": "4.4.4",
|
|
68
68
|
"eslint-plugin-import-x": "4.16.1",
|
|
69
69
|
"eslint-plugin-sonarjs": "3.0.4",
|
|
@@ -72,9 +72,9 @@
|
|
|
72
72
|
"knip": "5.61.3",
|
|
73
73
|
"markdownlint-cli2": "0.18.1",
|
|
74
74
|
"npm-run-all2": "8.0.4",
|
|
75
|
-
"oxlint": "1.
|
|
75
|
+
"oxlint": "1.7.0",
|
|
76
76
|
"rimraf": "6.0.1",
|
|
77
77
|
"typescript": "5.8.3",
|
|
78
|
-
"typescript-eslint": "8.
|
|
78
|
+
"typescript-eslint": "8.37.0"
|
|
79
79
|
}
|
|
80
80
|
}
|
package/dist/src/lib_datetime.js
CHANGED
|
@@ -32,18 +32,10 @@ export function datetime_format_utc_iso_hms(date) {
|
|
|
32
32
|
return date.toISOString().slice(11, 19);
|
|
33
33
|
}
|
|
34
34
|
export function datetime_format_utc_timestamp_alpha(date) {
|
|
35
|
-
|
|
36
|
-
const s2 = s1.replaceAll(DASH, EMPTY);
|
|
37
|
-
const s3 = s2.replaceAll(COLON, EMPTY);
|
|
38
|
-
const s4 = s3 + "Z";
|
|
39
|
-
return s4;
|
|
35
|
+
return date.toISOString().slice(0, 19).replaceAll(DASH, EMPTY).replaceAll(COLON, EMPTY) + "Z";
|
|
40
36
|
}
|
|
41
37
|
export function datetime_format_utc_timestamp_numeric(date) {
|
|
42
|
-
|
|
43
|
-
const s2 = s1.replaceAll(DASH, EMPTY);
|
|
44
|
-
const s3 = s2.replaceAll(COLON, EMPTY);
|
|
45
|
-
const s4 = s3.replace("T", EMPTY);
|
|
46
|
-
return s4;
|
|
38
|
+
return date.toISOString().slice(0, 19).replaceAll(DASH, EMPTY).replaceAll(COLON, EMPTY).replace("T", EMPTY);
|
|
47
39
|
}
|
|
48
40
|
function datetime_localize(date) {
|
|
49
41
|
return new Date(date.valueOf() - date.getTimezoneOffset() * 60_000);
|
|
@@ -5,16 +5,17 @@ const model_name_fallback = "claude-3.5-haiku";
|
|
|
5
5
|
const model_name_options = [
|
|
6
6
|
"claude-3.5-haiku",
|
|
7
7
|
"deepseek-v3",
|
|
8
|
-
"
|
|
8
|
+
"devstral-medium",
|
|
9
9
|
"devstral-small",
|
|
10
|
-
"ernie-4.5-300b",
|
|
11
10
|
"gemini-2.0-flash",
|
|
12
11
|
"gemini-2.5-flash",
|
|
13
12
|
"gpt-4.1-mini", // the best
|
|
14
13
|
"gpt-4.1-nano",
|
|
15
14
|
"gpt-4o-mini",
|
|
16
15
|
"grok-3-mini",
|
|
16
|
+
"kimi-k2",
|
|
17
17
|
"llama-4-maverick",
|
|
18
|
+
"mercury-coder",
|
|
18
19
|
"mistral-medium-3",
|
|
19
20
|
"qwen3-235b-a22b",
|
|
20
21
|
];
|
package/dist/src/lib_error.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { abort_with_error } from "./lib_abort.js";
|
|
2
|
+
import { LF } from "./lib_char_control.js";
|
|
2
3
|
export function error_ignore(_error) {
|
|
3
4
|
/* intentionally left empty */
|
|
4
5
|
}
|
|
@@ -9,13 +10,14 @@ export function error_get_text(error) {
|
|
|
9
10
|
return error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
10
11
|
}
|
|
11
12
|
export function error_get_message(error) {
|
|
12
|
-
|
|
13
|
+
const message_perhaps_multiline = error instanceof Error
|
|
13
14
|
? error.name === "Error"
|
|
14
15
|
? error.message
|
|
15
16
|
: `${error.name}: ${error.message}`
|
|
16
17
|
: String(error);
|
|
18
|
+
return message_perhaps_multiline.split(LF)[0] || "Blank Error";
|
|
17
19
|
}
|
|
18
20
|
export function error_abort(error) {
|
|
19
|
-
const
|
|
20
|
-
abort_with_error(
|
|
21
|
+
const message_perhaps_multiline = `Unhandled error: ${error_get_text(error)}`;
|
|
22
|
+
abort_with_error(message_perhaps_multiline);
|
|
21
23
|
}
|
|
@@ -18,13 +18,13 @@ export function llm_access_available({ llm_model_details, llm_model_name, llm_ex
|
|
|
18
18
|
return true;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
if (
|
|
22
|
-
if (llm_provider_get_api_key("
|
|
21
|
+
if (llm_model_code_openrouter !== null) {
|
|
22
|
+
if (llm_provider_get_api_key("openrouter")) {
|
|
23
23
|
return true;
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
if (
|
|
27
|
-
if (llm_provider_get_api_key("
|
|
26
|
+
if (llm_model_code_requesty !== null) {
|
|
27
|
+
if (llm_provider_get_api_key("requesty")) {
|
|
28
28
|
return true;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -41,29 +41,29 @@ export function llm_access_get({ llm_model_details, llm_model_name, llm_router,
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
if (llm_model_code_requesty !== null) {
|
|
45
|
-
const llm_api_key = llm_provider_get_api_key("requesty");
|
|
46
|
-
if (llm_api_key) {
|
|
47
|
-
return { llm_model_code: llm_model_code_requesty, llm_provider: "requesty", llm_api_key };
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
44
|
if (llm_model_code_openrouter !== null) {
|
|
51
45
|
const llm_api_key = llm_provider_get_api_key("openrouter");
|
|
52
46
|
if (llm_api_key) {
|
|
53
47
|
return { llm_model_code: llm_model_code_openrouter, llm_provider: "openrouter", llm_api_key };
|
|
54
48
|
}
|
|
55
49
|
}
|
|
50
|
+
if (llm_model_code_requesty !== null) {
|
|
51
|
+
const llm_api_key = llm_provider_get_api_key("requesty");
|
|
52
|
+
if (llm_api_key) {
|
|
53
|
+
return { llm_model_code: llm_model_code_requesty, llm_provider: "requesty", llm_api_key };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
56
|
if (llm_model_code_direct !== null && llm_provider !== null) {
|
|
57
57
|
const llm_api_key = llm_provider_get_api_key(llm_provider);
|
|
58
58
|
if (llm_api_key) {
|
|
59
59
|
return { llm_model_code: llm_model_code_direct, llm_provider, llm_api_key };
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
const env_requesty = llm_provider_get_api_key_env("requesty");
|
|
63
62
|
const env_openrouter = llm_provider_get_api_key_env("openrouter");
|
|
63
|
+
const env_requesty = llm_provider_get_api_key_env("requesty");
|
|
64
64
|
if (llm_provider !== null) {
|
|
65
65
|
const env_provider = llm_provider_get_api_key_env(llm_provider);
|
|
66
|
-
abort_with_error(`Please set environment variable ${
|
|
66
|
+
abort_with_error(`Please set environment variable ${env_provider}, ${env_openrouter} or ${env_requesty}`);
|
|
67
67
|
}
|
|
68
|
-
abort_with_error(`Please set environment variable ${
|
|
68
|
+
abort_with_error(`Please set environment variable ${env_openrouter} or ${env_requesty}`);
|
|
69
69
|
}
|
|
@@ -66,15 +66,26 @@ const LLM_MODEL_DETAILS = [
|
|
|
66
66
|
cents_output: 219,
|
|
67
67
|
has_structured_json: true,
|
|
68
68
|
},
|
|
69
|
+
{
|
|
70
|
+
llm_model_name: "devstral-medium",
|
|
71
|
+
llm_provider: null,
|
|
72
|
+
llm_model_code_direct: "devstral-medium-latest",
|
|
73
|
+
llm_model_code_requesty: "mistral/devstral-medium-latest",
|
|
74
|
+
llm_model_code_openrouter: "mistralai/devstral-medium",
|
|
75
|
+
context_window: 128_000,
|
|
76
|
+
cents_input: 40,
|
|
77
|
+
cents_output: 200,
|
|
78
|
+
has_structured_json: true,
|
|
79
|
+
},
|
|
69
80
|
{
|
|
70
81
|
llm_model_name: "devstral-small",
|
|
71
82
|
llm_provider: null,
|
|
72
|
-
llm_model_code_direct:
|
|
83
|
+
llm_model_code_direct: "devstral-small-latest",
|
|
73
84
|
llm_model_code_requesty: "mistral/devstral-small-latest",
|
|
74
85
|
llm_model_code_openrouter: "mistralai/devstral-small",
|
|
75
86
|
context_window: 128_000,
|
|
76
|
-
cents_input:
|
|
77
|
-
cents_output:
|
|
87
|
+
cents_input: 10,
|
|
88
|
+
cents_output: 30,
|
|
78
89
|
has_structured_json: true,
|
|
79
90
|
},
|
|
80
91
|
{
|
|
@@ -220,6 +231,17 @@ const LLM_MODEL_DETAILS = [
|
|
|
220
231
|
cents_output: 1500,
|
|
221
232
|
has_structured_json: true,
|
|
222
233
|
},
|
|
234
|
+
{
|
|
235
|
+
llm_model_name: "kimi-k2",
|
|
236
|
+
llm_provider: null,
|
|
237
|
+
llm_model_code_direct: "kimi-k2-0711-preview",
|
|
238
|
+
llm_model_code_requesty: null /* "novita/moonshotai/kimi-k2-instruct" */,
|
|
239
|
+
llm_model_code_openrouter: "moonshotai/kimi-k2",
|
|
240
|
+
context_window: 131_072,
|
|
241
|
+
cents_input: 60,
|
|
242
|
+
cents_output: 250,
|
|
243
|
+
has_structured_json: true,
|
|
244
|
+
},
|
|
223
245
|
{
|
|
224
246
|
llm_model_name: "llama-4-maverick",
|
|
225
247
|
llm_provider: null,
|
|
@@ -227,8 +249,8 @@ const LLM_MODEL_DETAILS = [
|
|
|
227
249
|
llm_model_code_requesty: "parasail/meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8",
|
|
228
250
|
llm_model_code_openrouter: "meta-llama/llama-4-maverick",
|
|
229
251
|
context_window: 1_048_576,
|
|
230
|
-
cents_input:
|
|
231
|
-
cents_output:
|
|
252
|
+
cents_input: 15,
|
|
253
|
+
cents_output: 60,
|
|
232
254
|
has_structured_json: true,
|
|
233
255
|
},
|
|
234
256
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnowennixon/diffdash",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.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",
|
|
@@ -20,30 +20,30 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@ai-sdk/anthropic": "1.2.12",
|
|
23
|
-
"@ai-sdk/deepseek": "0.2.
|
|
23
|
+
"@ai-sdk/deepseek": "0.2.16",
|
|
24
24
|
"@ai-sdk/google": "1.2.22",
|
|
25
|
-
"@ai-sdk/openai": "1.3.
|
|
25
|
+
"@ai-sdk/openai": "1.3.23",
|
|
26
26
|
"@openrouter/ai-sdk-provider": "0.7.2",
|
|
27
27
|
"@requesty/ai-sdk": "0.0.9",
|
|
28
|
-
"ai": "4.3.
|
|
28
|
+
"ai": "4.3.19",
|
|
29
29
|
"ansis": "4.1.0",
|
|
30
30
|
"argparse": "2.0.1",
|
|
31
31
|
"cli-table3": "0.6.5",
|
|
32
32
|
"simple-git": "3.28.0",
|
|
33
|
-
"zod": "3.25.
|
|
33
|
+
"zod": "3.25.76"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@biomejs/biome": "2.
|
|
36
|
+
"@biomejs/biome": "2.1.1",
|
|
37
37
|
"@eslint/eslintrc": "3.3.1",
|
|
38
|
-
"@eslint/js": "9.
|
|
38
|
+
"@eslint/js": "9.31.0",
|
|
39
39
|
"@johnowennixon/add-shebangs": "1.1.0",
|
|
40
40
|
"@johnowennixon/chmodx": "2.0.0",
|
|
41
|
-
"@stylistic/eslint-plugin": "5.
|
|
41
|
+
"@stylistic/eslint-plugin": "5.2.0",
|
|
42
42
|
"@types/argparse": "2.0.17",
|
|
43
|
-
"@types/node": "24.0.
|
|
44
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
45
|
-
"@typescript-eslint/parser": "8.
|
|
46
|
-
"eslint": "9.
|
|
43
|
+
"@types/node": "24.0.14",
|
|
44
|
+
"@typescript-eslint/eslint-plugin": "8.37.0",
|
|
45
|
+
"@typescript-eslint/parser": "8.37.0",
|
|
46
|
+
"eslint": "9.31.0",
|
|
47
47
|
"eslint-import-resolver-typescript": "4.4.4",
|
|
48
48
|
"eslint-plugin-import-x": "4.16.1",
|
|
49
49
|
"eslint-plugin-sonarjs": "3.0.4",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
"knip": "5.61.3",
|
|
53
53
|
"markdownlint-cli2": "0.18.1",
|
|
54
54
|
"npm-run-all2": "8.0.4",
|
|
55
|
-
"oxlint": "1.
|
|
55
|
+
"oxlint": "1.7.0",
|
|
56
56
|
"rimraf": "6.0.1",
|
|
57
57
|
"typescript": "5.8.3",
|
|
58
|
-
"typescript-eslint": "8.
|
|
58
|
+
"typescript-eslint": "8.37.0"
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"build": "run-s -ls build:clean build:tsc build:shebang build:chmod",
|