@johnowennixon/diffdash 1.9.0 → 1.11.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 +7 -4
- package/dist/package.json +22 -21
- package/dist/src/lib_char_digit.js +1 -0
- package/dist/src/lib_char_smart.js +8 -0
- package/dist/src/lib_cli.js +1 -57
- package/dist/src/lib_diffdash_cli.js +3 -2
- package/dist/src/lib_diffdash_config.js +2 -1
- package/dist/src/lib_diffdash_llm.js +1 -1
- package/dist/src/lib_diffdash_sequence.js +26 -9
- package/dist/src/lib_git_message_generate.js +9 -7
- package/dist/src/lib_git_message_prompt.js +4 -0
- package/dist/src/lib_llm_chat.js +14 -9
- package/dist/src/lib_llm_list.js +1 -0
- package/dist/src/lib_llm_model.js +184 -78
- package/dist/src/lib_secret_check.js +109 -0
- package/dist/src/lib_text.js +39 -0
- package/package.json +22 -21
package/README.md
CHANGED
|
@@ -118,7 +118,7 @@ diffdash --debug-llm-prompts
|
|
|
118
118
|
All command-line arguments are optional.
|
|
119
119
|
|
|
120
120
|
| Argument | Description |
|
|
121
|
-
|
|
121
|
+
| -------- | ----------- |
|
|
122
122
|
| `--help` | show a help message and exit |
|
|
123
123
|
| `--version` | show program version information and exit |
|
|
124
124
|
| `--auto-add` | automatically stage all changes without confirmation |
|
|
@@ -126,17 +126,18 @@ All command-line arguments are optional.
|
|
|
126
126
|
| `--auto-push` | automatically push changes after commit without confirmation |
|
|
127
127
|
| `--disable-add` | disable adding unstaged changes - exit if no changes staged |
|
|
128
128
|
| `--disable-status` | disable listing the staged files before generating a message |
|
|
129
|
-
| `--disable-preview` | disable previewing the generated message|
|
|
129
|
+
| `--disable-preview` | disable previewing the generated message |
|
|
130
130
|
| `--disable-commit` | disable committing changes - exit after generating the message |
|
|
131
131
|
| `--disable-push` | disable pushing changes - exit after making the commit |
|
|
132
132
|
| `--add-prefix PREFIX` | add a prefix to the commit message summary line |
|
|
133
133
|
| `--add-suffix SUFFIX` | add a suffix to the commit message summary line |
|
|
134
|
-
| `--no-verify` | bypass git hooks when committing or pushing to Git |
|
|
135
|
-
| `--force` | apply force when pushing to Git |
|
|
136
134
|
| `--llm-list` | display a list of available Large Language Models and exit |
|
|
137
135
|
| `--llm-compare` | compare the generated messages from all models - but do not commit |
|
|
138
136
|
| `--llm-model MODEL` | choose the LLM model by name (the default is normally best) |
|
|
139
137
|
| `--llm-excludes MODELS` | models to exclude from comparison (comma separated) |
|
|
138
|
+
| `--no-secret-check` | bypass checking for secrets in diffs |
|
|
139
|
+
| `--no-verify` | bypass git hooks when committing or pushing to Git |
|
|
140
|
+
| `--force` | apply force when pushing to Git |
|
|
140
141
|
| `--just-output` | just output the commit message for use in scripts |
|
|
141
142
|
| `--silent` | suppress all normal output - errors and aborts still display |
|
|
142
143
|
| `--debug-llm-prompts` | show prompts sent to the LLM |
|
|
@@ -153,6 +154,8 @@ Files containing secrets should not be in Git. But if they are, you can add an e
|
|
|
153
154
|
.env -diff
|
|
154
155
|
```
|
|
155
156
|
|
|
157
|
+
There is a rudimentary check for secrets in diffs before submitting to the LLM. If any are found, there is an interactive option to ignore. If you want to bypass this check, you can use the `--no-secret-check` flag.
|
|
158
|
+
|
|
156
159
|
## Development
|
|
157
160
|
|
|
158
161
|
To install on your laptop:
|
package/dist/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnowennixon/diffdash",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.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",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/johnowennixon/diffdash.git"
|
|
9
|
+
"url": "git+https://github.com/johnowennixon/diffdash.git"
|
|
10
10
|
},
|
|
11
11
|
"engines": {
|
|
12
12
|
"node": ">=20"
|
|
@@ -42,33 +42,34 @@
|
|
|
42
42
|
"test": "run-s -ls lint build"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@ai-sdk/anthropic": "2.0.
|
|
46
|
-
"@ai-sdk/deepseek": "1.0.
|
|
47
|
-
"@ai-sdk/google": "2.0.
|
|
48
|
-
"@ai-sdk/openai": "2.0.
|
|
49
|
-
"@inquirer/prompts": "
|
|
50
|
-
"@openrouter/ai-sdk-provider": "1.
|
|
51
|
-
"ai": "5.0.
|
|
52
|
-
"ansis": "4.
|
|
45
|
+
"@ai-sdk/anthropic": "2.0.53",
|
|
46
|
+
"@ai-sdk/deepseek": "1.0.31",
|
|
47
|
+
"@ai-sdk/google": "2.0.44",
|
|
48
|
+
"@ai-sdk/openai": "2.0.77",
|
|
49
|
+
"@inquirer/prompts": "8.0.2",
|
|
50
|
+
"@openrouter/ai-sdk-provider": "1.2.3",
|
|
51
|
+
"ai": "5.0.102",
|
|
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
|
-
"
|
|
57
|
-
"
|
|
56
|
+
"magic-regexp": "0.10.0",
|
|
57
|
+
"simple-git": "3.30.0",
|
|
58
|
+
"zod": "4.1.13"
|
|
58
59
|
},
|
|
59
60
|
"devDependencies": {
|
|
60
|
-
"@biomejs/biome": "2.
|
|
61
|
-
"@candide/tsgolint": "1.
|
|
61
|
+
"@biomejs/biome": "2.3.8",
|
|
62
|
+
"@candide/tsgolint": "1.4.0",
|
|
62
63
|
"@johnowennixon/add-shebangs": "1.1.0",
|
|
63
64
|
"@johnowennixon/chmodx": "2.1.0",
|
|
64
65
|
"@types/argparse": "2.0.17",
|
|
65
|
-
"@types/node": "24.
|
|
66
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
67
|
-
"knip": "5.
|
|
68
|
-
"markdownlint-cli2": "0.
|
|
66
|
+
"@types/node": "24.10.1",
|
|
67
|
+
"@typescript/native-preview": "7.0.0-dev.20251022.1",
|
|
68
|
+
"knip": "5.71.0",
|
|
69
|
+
"markdownlint-cli2": "0.19.1",
|
|
69
70
|
"npm-run-all2": "8.0.4",
|
|
70
|
-
"oxlint": "1.
|
|
71
|
-
"rimraf": "6.
|
|
72
|
-
"typescript": "5.9.
|
|
71
|
+
"oxlint": "1.31.0",
|
|
72
|
+
"rimraf": "6.1.2",
|
|
73
|
+
"typescript": "5.9.3"
|
|
73
74
|
}
|
|
74
75
|
}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
+
import { QUOTE_DOUBLE, QUOTE_SINGLE } from "./lib_char_punctuation.js";
|
|
1
2
|
export const LEFT_DOUBLE_QUOTATION_MARK = "“";
|
|
2
3
|
export const LEFT_SINGLE_QUOTATION_MARK = "‘";
|
|
3
4
|
export const RIGHT_DOUBLE_QUOTATION_MARK = "”";
|
|
4
5
|
export const RIGHT_SINGLE_QUOTATION_MARK = "’";
|
|
6
|
+
export function char_smart_remove(text) {
|
|
7
|
+
return text
|
|
8
|
+
.replaceAll(LEFT_DOUBLE_QUOTATION_MARK, QUOTE_DOUBLE)
|
|
9
|
+
.replaceAll(LEFT_SINGLE_QUOTATION_MARK, QUOTE_SINGLE)
|
|
10
|
+
.replaceAll(RIGHT_DOUBLE_QUOTATION_MARK, QUOTE_DOUBLE)
|
|
11
|
+
.replaceAll(RIGHT_SINGLE_QUOTATION_MARK, QUOTE_SINGLE);
|
|
12
|
+
}
|
package/dist/src/lib_cli.js
CHANGED
|
@@ -17,12 +17,6 @@ export function cli_integer_always(options = {}) {
|
|
|
17
17
|
export function cli_boolean(options = {}) {
|
|
18
18
|
return { kind: "boolean", options, value: false };
|
|
19
19
|
}
|
|
20
|
-
export function cli_command_sync(command_sync, options = {}) {
|
|
21
|
-
return { kind: "boolean", options, value: false, command_sync };
|
|
22
|
-
}
|
|
23
|
-
export function cli_command_async(command_async, options = {}) {
|
|
24
|
-
return { kind: "boolean", options, value: false, command_async };
|
|
25
|
-
}
|
|
26
20
|
export function cli_choice_optional(options = {}) {
|
|
27
21
|
return { kind: "choice", options, value: undefined };
|
|
28
22
|
}
|
|
@@ -126,50 +120,6 @@ function cli_recursive_parse({ schema, namespace, predicate, }) {
|
|
|
126
120
|
}
|
|
127
121
|
return result;
|
|
128
122
|
}
|
|
129
|
-
function cli_recursive_despatch_sync({ schema, namespace, parsed_args, }) {
|
|
130
|
-
for (const key in schema) {
|
|
131
|
-
if (!Object.hasOwn(schema, key)) {
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
const cli = schema[key];
|
|
135
|
-
if (!cli) {
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
if (cli.kind === "meg") {
|
|
139
|
-
const nested_schema = cli.value;
|
|
140
|
-
cli_recursive_despatch_sync({ schema: nested_schema, namespace, parsed_args });
|
|
141
|
-
}
|
|
142
|
-
else if (cli.kind === "boolean") {
|
|
143
|
-
if (namespace[key]) {
|
|
144
|
-
if (cli.command_sync) {
|
|
145
|
-
cli.command_sync(parsed_args);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
async function cli_recursive_despatch_async({ schema, namespace, parsed_args, }) {
|
|
152
|
-
for (const key in schema) {
|
|
153
|
-
if (!Object.hasOwn(schema, key)) {
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
const cli = schema[key];
|
|
157
|
-
if (!cli) {
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
if (cli.kind === "meg") {
|
|
161
|
-
const nested_schema = cli.value;
|
|
162
|
-
await cli_recursive_despatch_async({ schema: nested_schema, namespace, parsed_args });
|
|
163
|
-
}
|
|
164
|
-
else if (cli.kind === "boolean") {
|
|
165
|
-
if (namespace[key]) {
|
|
166
|
-
if (cli.command_async) {
|
|
167
|
-
await cli.command_async(parsed_args);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
123
|
export function cli_make_parser({ cli_schema, description, }) {
|
|
174
124
|
const argument_parser_options = { description, allow_abbrev: false };
|
|
175
125
|
const parser = new ArgumentParser(argument_parser_options);
|
|
@@ -177,11 +127,5 @@ export function cli_make_parser({ cli_schema, description, }) {
|
|
|
177
127
|
const namespace = parser.parse_args();
|
|
178
128
|
debug_inspect_when(debug_channels.cli, namespace, "namespace");
|
|
179
129
|
const parsed_args = cli_recursive_parse({ schema: cli_schema, namespace });
|
|
180
|
-
|
|
181
|
-
cli_recursive_despatch_sync({ schema: cli_schema, namespace, parsed_args });
|
|
182
|
-
}
|
|
183
|
-
async function despatch_async() {
|
|
184
|
-
await cli_recursive_despatch_async({ schema: cli_schema, namespace, parsed_args });
|
|
185
|
-
}
|
|
186
|
-
return { parsed_args, despatch_sync, despatch_async };
|
|
130
|
+
return { parsed_args };
|
|
187
131
|
}
|
|
@@ -10,8 +10,6 @@ const diffdash_cli_schema = {
|
|
|
10
10
|
disable_preview: cli_boolean({ help: "disable previewing the generated message" }),
|
|
11
11
|
disable_commit: cli_boolean({ help: "disable committing changes - exit after generating the message" }),
|
|
12
12
|
disable_push: cli_boolean({ help: "disable pushing changes - exit after making the commit" }),
|
|
13
|
-
no_verify: cli_boolean({ help: "bypass git hooks when committing or pushing to Git" }),
|
|
14
|
-
force: cli_boolean({ help: "apply force when pushing to Git" }),
|
|
15
13
|
add_prefix: cli_string({ help: "add a prefix to the commit message summary line", metavar: "PREFIX" }),
|
|
16
14
|
add_suffix: cli_string({ help: "add a suffix to the commit message summary line", metavar: "SUFFIX" }),
|
|
17
15
|
llm_list: cli_boolean({ help: "display a list of available Large Language Models and exit" }),
|
|
@@ -22,6 +20,9 @@ const diffdash_cli_schema = {
|
|
|
22
20
|
default: diffdash_llm_model_default,
|
|
23
21
|
}),
|
|
24
22
|
llm_excludes: cli_string({ help: "models to exclude from comparison (comma separated)", metavar: "MODELS" }),
|
|
23
|
+
no_secret_check: cli_boolean({ help: "bypass checking for secrets in diffs" }),
|
|
24
|
+
no_verify: cli_boolean({ help: "bypass git hooks when committing or pushing to Git" }),
|
|
25
|
+
force: cli_boolean({ help: "apply force when pushing to Git" }),
|
|
25
26
|
just_output: cli_boolean({ help: "just output the commit message for use in scripts" }),
|
|
26
27
|
silent: cli_boolean({ help: "suppress all normal output - errors and aborts still display" }),
|
|
27
28
|
debug_llm_prompts: cli_boolean({ help: "debug prompts sent to the LLM" }),
|
|
@@ -33,7 +33,7 @@ function diffdash_config_file_read(config) {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
export function diffdash_config_get() {
|
|
36
|
-
const { version, auto_add, auto_commit, auto_push, disable_add, disable_commit, disable_preview, disable_status, disable_push,
|
|
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
37
|
if (version) {
|
|
38
38
|
tell_plain(`${PACKAGE_NAME} v${PACKAGE_VERSION}`);
|
|
39
39
|
process.exit(0);
|
|
@@ -58,6 +58,7 @@ export function diffdash_config_get() {
|
|
|
58
58
|
disable_push,
|
|
59
59
|
add_prefix,
|
|
60
60
|
add_suffix,
|
|
61
|
+
no_secret_check,
|
|
61
62
|
no_verify,
|
|
62
63
|
force,
|
|
63
64
|
llm_compare,
|
|
@@ -13,7 +13,7 @@ const model_name_options = [
|
|
|
13
13
|
"gpt-5-nano",
|
|
14
14
|
"gpt-5-nano-minimal",
|
|
15
15
|
"grok-code-fast-1",
|
|
16
|
-
"llama-4-maverick@
|
|
16
|
+
"llama-4-maverick@groq",
|
|
17
17
|
];
|
|
18
18
|
export const diffdash_llm_model_details = llm_model_get_details({ llm_model_names: model_name_options });
|
|
19
19
|
export const diffdash_llm_model_choices = llm_model_get_choices({ llm_model_details: diffdash_llm_model_details });
|
|
@@ -2,13 +2,14 @@ import { abort_with_error, abort_with_warning } from "./lib_abort.js";
|
|
|
2
2
|
import { ansi_blue } from "./lib_ansi.js";
|
|
3
3
|
import { debug_channels, debug_inspect } from "./lib_debug.js";
|
|
4
4
|
import { diffdash_add_footer, diffdash_add_prefix_or_suffix } from "./lib_diffdash_add.js";
|
|
5
|
-
import { error_get_text } from "./lib_error.js";
|
|
5
|
+
import { error_get_message, error_get_text } from "./lib_error.js";
|
|
6
6
|
import { git_message_display } from "./lib_git_message_display.js";
|
|
7
7
|
import { git_message_generate_result } from "./lib_git_message_generate.js";
|
|
8
8
|
import { git_message_validate_check, git_message_validate_get_result } from "./lib_git_message_validate.js";
|
|
9
9
|
import { git_simple_open_check_not_bare, git_simple_open_git_repo } from "./lib_git_simple_open.js";
|
|
10
10
|
import { git_simple_staging_create_commit, git_simple_staging_get_staged_diff, git_simple_staging_get_staged_diffstat, git_simple_staging_has_staged_changes, git_simple_staging_has_unstaged_changes, git_simple_staging_push_to_remote, git_simple_staging_stage_all_changes, } from "./lib_git_simple_staging.js";
|
|
11
11
|
import { llm_results_summary } from "./lib_llm_results.js";
|
|
12
|
+
import { secret_check } from "./lib_secret_check.js";
|
|
12
13
|
import { stdio_write_stdout, stdio_write_stdout_linefeed } from "./lib_stdio_write.js";
|
|
13
14
|
import { tell_action, tell_info, tell_plain, tell_success, tell_warning } from "./lib_tell.js";
|
|
14
15
|
import { tui_confirm } from "./lib_tui_confirm.js";
|
|
@@ -92,13 +93,21 @@ async function phase_status({ config, git }) {
|
|
|
92
93
|
}
|
|
93
94
|
async function phase_compare({ config, git }) {
|
|
94
95
|
const { silent } = config;
|
|
95
|
-
|
|
96
|
-
tell_action("Generating Git commit messages using all models in parallel");
|
|
97
|
-
}
|
|
98
|
-
const { all_llm_configs, add_prefix, add_suffix, extra_prompts } = config;
|
|
96
|
+
const { all_llm_configs, add_prefix, add_suffix, no_secret_check, extra_prompts } = config;
|
|
99
97
|
const diffstat = await git_simple_staging_get_staged_diffstat(git);
|
|
100
98
|
const diff = await git_simple_staging_get_staged_diff(git);
|
|
99
|
+
if (!no_secret_check) {
|
|
100
|
+
try {
|
|
101
|
+
await secret_check({ text: diff, interactive: true });
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
abort_with_error(`Aborting: ${error_get_message(error)}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
101
107
|
const inputs = { diffstat, diff, extra_prompts };
|
|
108
|
+
if (!silent) {
|
|
109
|
+
tell_action("Generating Git commit messages using all models in parallel");
|
|
110
|
+
}
|
|
102
111
|
const result_promises = all_llm_configs.map((llm_config) => git_message_generate_result({ llm_config, inputs }));
|
|
103
112
|
const all_results = await Promise.all(result_promises);
|
|
104
113
|
for (const result of all_results) {
|
|
@@ -120,14 +129,22 @@ async function phase_compare({ config, git }) {
|
|
|
120
129
|
llm_results_summary(all_results);
|
|
121
130
|
}
|
|
122
131
|
async function phase_generate({ config, git }) {
|
|
123
|
-
const { disable_preview, add_prefix, add_suffix, llm_config, just_output, silent, extra_prompts } = config;
|
|
132
|
+
const { disable_preview, add_prefix, add_suffix, llm_config, no_secret_check, just_output, silent, extra_prompts } = config;
|
|
124
133
|
const { llm_model_name } = llm_config;
|
|
125
|
-
if (!silent && !just_output) {
|
|
126
|
-
tell_action(`Generating the Git commit message using ${llm_model_name}`);
|
|
127
|
-
}
|
|
128
134
|
const diffstat = await git_simple_staging_get_staged_diffstat(git);
|
|
129
135
|
const diff = await git_simple_staging_get_staged_diff(git);
|
|
136
|
+
if (!no_secret_check) {
|
|
137
|
+
try {
|
|
138
|
+
await secret_check({ text: diff, interactive: true });
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
abort_with_error(`Aborting: ${error_get_message(error)}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
130
144
|
const inputs = { diffstat, diff, extra_prompts };
|
|
145
|
+
if (!silent && !just_output) {
|
|
146
|
+
tell_action(`Generating the Git commit message using ${llm_model_name}`);
|
|
147
|
+
}
|
|
131
148
|
const result = await git_message_generate_result({ llm_config, inputs });
|
|
132
149
|
const { error_text } = result;
|
|
133
150
|
if (error_text !== null) {
|
|
@@ -4,22 +4,23 @@ import { git_message_prompt_get_system, git_message_prompt_get_user } from "./li
|
|
|
4
4
|
import { git_message_schema, git_message_schema_format } from "./lib_git_message_schema.js";
|
|
5
5
|
import { llm_chat_generate_object, llm_chat_generate_text } from "./lib_llm_chat.js";
|
|
6
6
|
import { llm_tokens_debug_usage, llm_tokens_estimate_length_from_tokens, llm_tokens_estimate_tokens_from_length, } from "./lib_llm_tokens.js";
|
|
7
|
-
async function git_message_generate_unstructured({ llm_config, system_prompt, user_prompt, }) {
|
|
8
|
-
const outputs = await llm_chat_generate_text({ llm_config, system_prompt, user_prompt });
|
|
7
|
+
async function git_message_generate_unstructured({ llm_config, system_prompt, user_prompt, max_output_tokens, }) {
|
|
8
|
+
const outputs = await llm_chat_generate_text({ llm_config, system_prompt, user_prompt, max_output_tokens });
|
|
9
9
|
return outputs;
|
|
10
10
|
}
|
|
11
|
-
async function git_message_generate_structured({ llm_config, system_prompt, user_prompt, }) {
|
|
11
|
+
async function git_message_generate_structured({ llm_config, system_prompt, user_prompt, max_output_tokens, }) {
|
|
12
12
|
const schema = git_message_schema;
|
|
13
13
|
const { generated_object, total_usage, provider_metadata } = await llm_chat_generate_object({
|
|
14
14
|
llm_config,
|
|
15
15
|
system_prompt,
|
|
16
16
|
user_prompt,
|
|
17
|
+
max_output_tokens,
|
|
17
18
|
schema,
|
|
18
19
|
});
|
|
19
20
|
const generated_text = git_message_schema_format(generated_object);
|
|
20
21
|
return { generated_text, reasoning_text: undefined, total_usage, provider_metadata };
|
|
21
22
|
}
|
|
22
|
-
|
|
23
|
+
async function git_message_generate_outputs({ llm_config, inputs, }) {
|
|
23
24
|
const { effective_context_window } = llm_config;
|
|
24
25
|
const { has_structured_json } = llm_config.llm_model_detail;
|
|
25
26
|
const system_prompt = git_message_prompt_get_system({ has_structured_json, inputs });
|
|
@@ -30,10 +31,11 @@ export async function git_message_generate_string({ llm_config, inputs, }) {
|
|
|
30
31
|
inputs,
|
|
31
32
|
max_length: user_length,
|
|
32
33
|
});
|
|
34
|
+
const max_output_tokens = 8192; // This is the maximum for some models
|
|
33
35
|
llm_tokens_debug_usage({ name: "Inputs", llm_config, text: system_prompt + user_prompt });
|
|
34
36
|
const outputs = has_structured_json
|
|
35
|
-
? await git_message_generate_structured({ llm_config, system_prompt, user_prompt })
|
|
36
|
-
: await git_message_generate_unstructured({ llm_config, system_prompt, user_prompt });
|
|
37
|
+
? await git_message_generate_structured({ llm_config, system_prompt, user_prompt, max_output_tokens })
|
|
38
|
+
: await git_message_generate_unstructured({ llm_config, system_prompt, user_prompt, max_output_tokens });
|
|
37
39
|
llm_tokens_debug_usage({ name: "Outputs", llm_config, text: outputs.generated_text });
|
|
38
40
|
return outputs;
|
|
39
41
|
}
|
|
@@ -41,7 +43,7 @@ export async function git_message_generate_result({ llm_config, inputs, }) {
|
|
|
41
43
|
const duration = new Duration();
|
|
42
44
|
duration.start();
|
|
43
45
|
try {
|
|
44
|
-
const outputs = await
|
|
46
|
+
const outputs = await git_message_generate_outputs({ llm_config, inputs });
|
|
45
47
|
duration.stop();
|
|
46
48
|
const seconds = duration.seconds_rounded();
|
|
47
49
|
return { llm_config, seconds, error_text: null, outputs };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LF } from "./lib_char_control.js";
|
|
2
2
|
import { EMPTY } from "./lib_char_empty.js";
|
|
3
|
+
import { tell_warning } from "./lib_tell.js";
|
|
3
4
|
const LF_LF = LF + LF;
|
|
4
5
|
const portion_role = `
|
|
5
6
|
Your role is to generate a Git commit message in conversational English.
|
|
@@ -65,6 +66,9 @@ export function git_message_prompt_get_system({ has_structured_json, inputs, })
|
|
|
65
66
|
export function git_message_prompt_get_user({ has_structured_json, inputs, max_length, }) {
|
|
66
67
|
const { diffstat, diff } = inputs;
|
|
67
68
|
const truncate = diffstat.length + diff.length > max_length;
|
|
69
|
+
if (truncate) {
|
|
70
|
+
tell_warning("The Diff is too long to fit in the user prompt - it is being truncated");
|
|
71
|
+
}
|
|
68
72
|
const diff_truncated = truncate ? diff.slice(0, max_length - diffstat.length) + LF : diff;
|
|
69
73
|
let user_prompt = EMPTY;
|
|
70
74
|
user_prompt += "<diffstat>" + LF + diffstat + "</diffstat>" + LF_LF;
|
package/dist/src/lib_llm_chat.js
CHANGED
|
@@ -10,7 +10,7 @@ import { tui_block_string } from "./lib_tui_block.js";
|
|
|
10
10
|
function llm_chat_get_parameters() {
|
|
11
11
|
return {
|
|
12
12
|
max_output_tokens: parse_int_or_undefined(env_get_empty("lib_llm_chat_max_output_tokens")),
|
|
13
|
-
timeout: parse_int(env_get_substitute("lib_llm_chat_timeout", "
|
|
13
|
+
timeout: parse_int(env_get_substitute("lib_llm_chat_timeout", "90")),
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
function llm_chat_debug_prompts({ llm_model_name, system_prompt, user_prompt, }) {
|
|
@@ -22,7 +22,7 @@ function llm_chat_debug_prompts({ llm_model_name, system_prompt, user_prompt, })
|
|
|
22
22
|
tui_block_string({ teller, title: `LLM user prompt (for ${llm_model_name}):`, content: user_prompt });
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
export async function llm_chat_generate_text({ llm_config, system_prompt, user_prompt, tools, max_steps, min_steps, }) {
|
|
25
|
+
export async function llm_chat_generate_text({ llm_config, system_prompt, user_prompt, max_output_tokens, tools, max_steps, min_steps, }) {
|
|
26
26
|
const { llm_model_name, llm_model_detail, llm_model_code, llm_api_code, llm_api_key } = llm_config;
|
|
27
27
|
llm_chat_debug_prompts({ system_prompt, user_prompt, llm_model_name });
|
|
28
28
|
const ai_sdk_language_model = llm_api_get_ai_sdk_language_model({
|
|
@@ -30,9 +30,14 @@ export async function llm_chat_generate_text({ llm_config, system_prompt, user_p
|
|
|
30
30
|
llm_api_code,
|
|
31
31
|
llm_api_key,
|
|
32
32
|
});
|
|
33
|
-
const { recommended_temperature, provider_options } = llm_model_detail;
|
|
33
|
+
const { recommended_temperature, provider_options, max_output_tokens: max_output_tokens_model } = llm_model_detail;
|
|
34
34
|
const temperature = recommended_temperature;
|
|
35
|
-
const {
|
|
35
|
+
const { timeout, max_output_tokens: max_output_tokens_env } = llm_chat_get_parameters();
|
|
36
|
+
if (max_output_tokens_env !== undefined) {
|
|
37
|
+
max_output_tokens = max_output_tokens_env;
|
|
38
|
+
}
|
|
39
|
+
max_output_tokens =
|
|
40
|
+
max_output_tokens === undefined ? max_output_tokens_model : Math.min(max_output_tokens, max_output_tokens_model);
|
|
36
41
|
const llm_inputs = {
|
|
37
42
|
model: ai_sdk_language_model,
|
|
38
43
|
system: system_prompt,
|
|
@@ -57,11 +62,11 @@ export async function llm_chat_generate_text({ llm_config, system_prompt, user_p
|
|
|
57
62
|
const { text: generated_text, reasoningText: reasoning_text, totalUsage: total_usage, providerMetadata: provider_metadata, } = llm_outputs;
|
|
58
63
|
return { generated_text, reasoning_text, total_usage, provider_metadata };
|
|
59
64
|
}
|
|
60
|
-
export async function llm_chat_generate_text_result({ llm_config, system_prompt, user_prompt, }) {
|
|
65
|
+
export async function llm_chat_generate_text_result({ llm_config, system_prompt, user_prompt, max_output_tokens, }) {
|
|
61
66
|
const duration = new Duration();
|
|
62
67
|
duration.start();
|
|
63
68
|
try {
|
|
64
|
-
const outputs = await llm_chat_generate_text({ llm_config, system_prompt, user_prompt });
|
|
69
|
+
const outputs = await llm_chat_generate_text({ llm_config, system_prompt, user_prompt, max_output_tokens });
|
|
65
70
|
duration.stop();
|
|
66
71
|
const seconds = duration.seconds_rounded();
|
|
67
72
|
return { llm_config, seconds, error_text: null, outputs };
|
|
@@ -73,7 +78,7 @@ export async function llm_chat_generate_text_result({ llm_config, system_prompt,
|
|
|
73
78
|
return { llm_config, seconds, error_text, outputs: null };
|
|
74
79
|
}
|
|
75
80
|
}
|
|
76
|
-
export async function llm_chat_generate_object({ llm_config, user_prompt, system_prompt, schema, }) {
|
|
81
|
+
export async function llm_chat_generate_object({ llm_config, user_prompt, system_prompt, max_output_tokens, schema, }) {
|
|
77
82
|
const { llm_model_name, llm_model_detail, llm_model_code, llm_api_code, llm_api_key } = llm_config;
|
|
78
83
|
llm_chat_debug_prompts({ system_prompt, user_prompt, llm_model_name });
|
|
79
84
|
const ai_sdk_language_model = llm_api_get_ai_sdk_language_model({
|
|
@@ -83,14 +88,14 @@ export async function llm_chat_generate_object({ llm_config, user_prompt, system
|
|
|
83
88
|
});
|
|
84
89
|
const { recommended_temperature, provider_options } = llm_model_detail;
|
|
85
90
|
const temperature = recommended_temperature;
|
|
86
|
-
const {
|
|
91
|
+
const { timeout, max_output_tokens: max_output_tokens_env } = llm_chat_get_parameters();
|
|
87
92
|
const llm_inputs = {
|
|
88
93
|
model: ai_sdk_language_model,
|
|
89
94
|
system: system_prompt,
|
|
90
95
|
prompt: user_prompt,
|
|
91
96
|
output: "object",
|
|
92
97
|
schema,
|
|
93
|
-
maxOutputTokens: max_output_tokens,
|
|
98
|
+
maxOutputTokens: max_output_tokens_env ?? max_output_tokens,
|
|
94
99
|
temperature,
|
|
95
100
|
providerOptions: provider_options,
|
|
96
101
|
abortSignal: AbortSignal.timeout(timeout * 1000),
|
package/dist/src/lib_llm_list.js
CHANGED
|
@@ -18,6 +18,7 @@ export function llm_list_models({ llm_model_details }) {
|
|
|
18
18
|
table.push(row);
|
|
19
19
|
}
|
|
20
20
|
stdio_write_stdout_linefeed(table.toString());
|
|
21
|
+
tell_info(`This is a total of ${llm_model_details.length} models.`);
|
|
21
22
|
tell_info("Prices are per million tokens.");
|
|
22
23
|
tell_warning("Prices are best effort and are liable to change - always double-check with your LLM API provider.");
|
|
23
24
|
}
|
|
@@ -15,6 +15,15 @@ function provider_options_anthropic({ thinking }) {
|
|
|
15
15
|
}
|
|
16
16
|
: undefined;
|
|
17
17
|
}
|
|
18
|
+
function provider_options_google({ thinking_level }) {
|
|
19
|
+
return {
|
|
20
|
+
google: {
|
|
21
|
+
thinkingConfig: {
|
|
22
|
+
thinkingLevel: thinking_level,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
18
27
|
function provider_options_openai({ reasoning_effort, }) {
|
|
19
28
|
return {
|
|
20
29
|
openai: {
|
|
@@ -37,6 +46,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
37
46
|
llm_model_code: "claude-3-5-haiku-latest",
|
|
38
47
|
llm_api_code: "anthropic",
|
|
39
48
|
context_window: 200_000,
|
|
49
|
+
max_output_tokens: 8192,
|
|
40
50
|
cents_input: 80,
|
|
41
51
|
cents_output: 400,
|
|
42
52
|
default_reasoning: false,
|
|
@@ -45,22 +55,37 @@ export const LLM_MODEL_DETAILS = [
|
|
|
45
55
|
provider_options: provider_options_anthropic({ thinking: false }),
|
|
46
56
|
},
|
|
47
57
|
{
|
|
48
|
-
llm_model_name: "claude-
|
|
49
|
-
llm_model_code: "claude-
|
|
58
|
+
llm_model_name: "claude-opus-4.5",
|
|
59
|
+
llm_model_code: "claude-opus-4-5",
|
|
50
60
|
llm_api_code: "anthropic",
|
|
51
61
|
context_window: 200_000,
|
|
52
|
-
|
|
53
|
-
|
|
62
|
+
max_output_tokens: 64_000,
|
|
63
|
+
cents_input: 300, // for input tokens <= 200K
|
|
64
|
+
cents_output: 1500, // for input tokens <= 200K
|
|
54
65
|
default_reasoning: false,
|
|
55
66
|
has_structured_json: true,
|
|
56
67
|
recommended_temperature: undefined,
|
|
57
68
|
provider_options: provider_options_anthropic({ thinking: false }),
|
|
58
69
|
},
|
|
70
|
+
{
|
|
71
|
+
llm_model_name: "claude-opus-4.5-thinking",
|
|
72
|
+
llm_model_code: "claude-opus-4-5",
|
|
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
|
+
},
|
|
59
83
|
{
|
|
60
84
|
llm_model_name: "claude-sonnet-4",
|
|
61
85
|
llm_model_code: "claude-sonnet-4-0",
|
|
62
86
|
llm_api_code: "anthropic",
|
|
63
87
|
context_window: 200_000,
|
|
88
|
+
max_output_tokens: 64_000,
|
|
64
89
|
cents_input: 300,
|
|
65
90
|
cents_output: 1500,
|
|
66
91
|
default_reasoning: false,
|
|
@@ -73,6 +98,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
73
98
|
llm_model_code: "claude-sonnet-4-0",
|
|
74
99
|
llm_api_code: "anthropic",
|
|
75
100
|
context_window: 200_000,
|
|
101
|
+
max_output_tokens: 62_976, // = 64000 - 1024 used for reasoning
|
|
76
102
|
cents_input: 300,
|
|
77
103
|
cents_output: 1500,
|
|
78
104
|
default_reasoning: true,
|
|
@@ -81,22 +107,37 @@ export const LLM_MODEL_DETAILS = [
|
|
|
81
107
|
provider_options: provider_options_anthropic({ thinking: true }),
|
|
82
108
|
},
|
|
83
109
|
{
|
|
84
|
-
llm_model_name: "
|
|
85
|
-
llm_model_code: "
|
|
86
|
-
llm_api_code: "
|
|
87
|
-
context_window:
|
|
88
|
-
|
|
89
|
-
|
|
110
|
+
llm_model_name: "claude-sonnet-4.5",
|
|
111
|
+
llm_model_code: "claude-sonnet-4-5",
|
|
112
|
+
llm_api_code: "anthropic",
|
|
113
|
+
context_window: 200_000, // 1_000_000 available with context-1m beta header
|
|
114
|
+
max_output_tokens: 64_000,
|
|
115
|
+
cents_input: 300, // for input tokens <= 200K
|
|
116
|
+
cents_output: 1500, // for input tokens <= 200K
|
|
90
117
|
default_reasoning: false,
|
|
91
118
|
has_structured_json: true,
|
|
92
119
|
recommended_temperature: undefined,
|
|
93
|
-
provider_options:
|
|
120
|
+
provider_options: provider_options_anthropic({ thinking: false }),
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
llm_model_name: "claude-sonnet-4.5-thinking",
|
|
124
|
+
llm_model_code: "claude-sonnet-4-5",
|
|
125
|
+
llm_api_code: "anthropic",
|
|
126
|
+
context_window: 200_000, // 1_000_000 available with context-1m beta header
|
|
127
|
+
max_output_tokens: 62_976, // = 64000 - 1024 used for reasoning
|
|
128
|
+
cents_input: 300, // for input tokens <= 200K
|
|
129
|
+
cents_output: 1500, // for input tokens <= 200K
|
|
130
|
+
default_reasoning: false,
|
|
131
|
+
has_structured_json: true,
|
|
132
|
+
recommended_temperature: undefined,
|
|
133
|
+
provider_options: provider_options_anthropic({ thinking: true }),
|
|
94
134
|
},
|
|
95
135
|
{
|
|
96
136
|
llm_model_name: "deepseek-chat",
|
|
97
137
|
llm_model_code: "deepseek-chat",
|
|
98
138
|
llm_api_code: "deepseek",
|
|
99
139
|
context_window: 128_000,
|
|
140
|
+
max_output_tokens: 8192,
|
|
100
141
|
cents_input: 56,
|
|
101
142
|
cents_output: 168,
|
|
102
143
|
default_reasoning: false,
|
|
@@ -109,6 +150,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
109
150
|
llm_model_code: "deepseek-reasoner",
|
|
110
151
|
llm_api_code: "deepseek",
|
|
111
152
|
context_window: 128_000,
|
|
153
|
+
max_output_tokens: 65_536,
|
|
112
154
|
cents_input: 56,
|
|
113
155
|
cents_output: 168,
|
|
114
156
|
default_reasoning: true,
|
|
@@ -121,6 +163,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
121
163
|
llm_model_code: "mistralai/devstral-medium",
|
|
122
164
|
llm_api_code: "openrouter",
|
|
123
165
|
context_window: 128_000,
|
|
166
|
+
max_output_tokens: 128_000,
|
|
124
167
|
cents_input: 40,
|
|
125
168
|
cents_output: 200,
|
|
126
169
|
default_reasoning: false,
|
|
@@ -133,6 +176,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
133
176
|
llm_model_code: "mistralai/devstral-small",
|
|
134
177
|
llm_api_code: "openrouter",
|
|
135
178
|
context_window: 128_000,
|
|
179
|
+
max_output_tokens: 128_000,
|
|
136
180
|
cents_input: 10,
|
|
137
181
|
cents_output: 30,
|
|
138
182
|
default_reasoning: false,
|
|
@@ -145,6 +189,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
145
189
|
llm_model_code: "gemini-2.0-flash",
|
|
146
190
|
llm_api_code: "google",
|
|
147
191
|
context_window: 1_048_576,
|
|
192
|
+
max_output_tokens: 8192,
|
|
148
193
|
cents_input: 10,
|
|
149
194
|
cents_output: 40,
|
|
150
195
|
default_reasoning: false,
|
|
@@ -157,6 +202,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
157
202
|
llm_model_code: "gemini-2.5-flash",
|
|
158
203
|
llm_api_code: "google",
|
|
159
204
|
context_window: 1_048_576,
|
|
205
|
+
max_output_tokens: 65_536,
|
|
160
206
|
cents_input: 30,
|
|
161
207
|
cents_output: 250,
|
|
162
208
|
default_reasoning: false,
|
|
@@ -169,54 +215,85 @@ export const LLM_MODEL_DETAILS = [
|
|
|
169
215
|
llm_model_code: "gemini-2.5-pro",
|
|
170
216
|
llm_api_code: "google",
|
|
171
217
|
context_window: 1_048_576,
|
|
218
|
+
max_output_tokens: 65_536,
|
|
172
219
|
cents_input: 125,
|
|
173
220
|
cents_output: 1000,
|
|
174
|
-
default_reasoning:
|
|
221
|
+
default_reasoning: true,
|
|
175
222
|
has_structured_json: true,
|
|
176
223
|
recommended_temperature: undefined,
|
|
177
224
|
provider_options: undefined,
|
|
178
225
|
},
|
|
179
226
|
{
|
|
180
|
-
llm_model_name: "
|
|
181
|
-
llm_model_code: "
|
|
182
|
-
llm_api_code: "
|
|
183
|
-
context_window:
|
|
184
|
-
|
|
185
|
-
|
|
227
|
+
llm_model_name: "gemini-3-pro-preview-high",
|
|
228
|
+
llm_model_code: "gemini-3-pro-preview",
|
|
229
|
+
llm_api_code: "google",
|
|
230
|
+
context_window: 1_048_576,
|
|
231
|
+
max_output_tokens: 65_536,
|
|
232
|
+
cents_input: 200,
|
|
233
|
+
cents_output: 1200,
|
|
234
|
+
default_reasoning: true,
|
|
235
|
+
has_structured_json: true,
|
|
236
|
+
recommended_temperature: undefined,
|
|
237
|
+
provider_options: provider_options_google({ thinking_level: "high" }),
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
llm_model_name: "gemini-3-pro-preview-low",
|
|
241
|
+
llm_model_code: "gemini-3-pro-preview",
|
|
242
|
+
llm_api_code: "google",
|
|
243
|
+
context_window: 1_048_576,
|
|
244
|
+
max_output_tokens: 65_536,
|
|
245
|
+
cents_input: 200,
|
|
246
|
+
cents_output: 1200,
|
|
186
247
|
default_reasoning: false,
|
|
187
|
-
has_structured_json:
|
|
248
|
+
has_structured_json: true,
|
|
188
249
|
recommended_temperature: undefined,
|
|
189
|
-
provider_options:
|
|
250
|
+
provider_options: provider_options_google({ thinking_level: "low" }),
|
|
190
251
|
},
|
|
191
252
|
{
|
|
192
253
|
llm_model_name: "glm-4.5@z-ai",
|
|
193
254
|
llm_model_code: "z-ai/glm-4.5",
|
|
194
255
|
llm_api_code: "openrouter",
|
|
195
256
|
context_window: 128_000,
|
|
257
|
+
max_output_tokens: 96_000,
|
|
196
258
|
cents_input: 60,
|
|
197
259
|
cents_output: 220,
|
|
198
260
|
default_reasoning: true,
|
|
199
261
|
has_structured_json: false,
|
|
200
262
|
recommended_temperature: undefined,
|
|
201
|
-
provider_options: provider_options_openrouter({ only: "z-ai
|
|
263
|
+
provider_options: provider_options_openrouter({ only: "z-ai" }),
|
|
202
264
|
},
|
|
203
265
|
{
|
|
204
266
|
llm_model_name: "glm-4.5-air@z-ai",
|
|
205
267
|
llm_model_code: "z-ai/glm-4.5-air",
|
|
206
268
|
llm_api_code: "openrouter",
|
|
207
269
|
context_window: 128_000,
|
|
270
|
+
max_output_tokens: 96_000,
|
|
208
271
|
cents_input: 20,
|
|
209
272
|
cents_output: 110,
|
|
210
273
|
default_reasoning: true,
|
|
211
274
|
has_structured_json: false,
|
|
212
275
|
recommended_temperature: undefined,
|
|
213
|
-
provider_options: provider_options_openrouter({ only: "z-ai
|
|
276
|
+
provider_options: provider_options_openrouter({ only: "z-ai" }),
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
llm_model_name: "glm-4.6@z-ai",
|
|
280
|
+
llm_model_code: "z-ai/glm-4.6",
|
|
281
|
+
llm_api_code: "openrouter",
|
|
282
|
+
context_window: 128_000,
|
|
283
|
+
max_output_tokens: 96_000,
|
|
284
|
+
cents_input: 60,
|
|
285
|
+
cents_output: 220,
|
|
286
|
+
default_reasoning: true,
|
|
287
|
+
has_structured_json: false,
|
|
288
|
+
recommended_temperature: undefined,
|
|
289
|
+
provider_options: provider_options_openrouter({ only: "z-ai" }),
|
|
214
290
|
},
|
|
215
291
|
{
|
|
216
292
|
llm_model_name: "gpt-4.1",
|
|
217
293
|
llm_model_code: "gpt-4.1",
|
|
218
294
|
llm_api_code: "openai",
|
|
219
295
|
context_window: context_window_openai({ tier1: 200_000, unrestricted: 1_000_000 }),
|
|
296
|
+
max_output_tokens: 32_768,
|
|
220
297
|
cents_input: 200,
|
|
221
298
|
cents_output: 800,
|
|
222
299
|
default_reasoning: false,
|
|
@@ -229,6 +306,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
229
306
|
llm_model_code: "gpt-4.1-mini",
|
|
230
307
|
llm_api_code: "openai",
|
|
231
308
|
context_window: context_window_openai({ tier1: 400_000, unrestricted: 1_000_000 }),
|
|
309
|
+
max_output_tokens: 32_768,
|
|
232
310
|
cents_input: 40,
|
|
233
311
|
cents_output: 160,
|
|
234
312
|
default_reasoning: false,
|
|
@@ -241,6 +319,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
241
319
|
llm_model_code: "gpt-4.1-nano",
|
|
242
320
|
llm_api_code: "openai",
|
|
243
321
|
context_window: context_window_openai({ tier1: 400_000, unrestricted: 1_000_000 }),
|
|
322
|
+
max_output_tokens: 32_768,
|
|
244
323
|
cents_input: 10,
|
|
245
324
|
cents_output: 40,
|
|
246
325
|
default_reasoning: false,
|
|
@@ -253,6 +332,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
253
332
|
llm_model_code: "gpt-5",
|
|
254
333
|
llm_api_code: "openai",
|
|
255
334
|
context_window: context_window_openai({ tier1: 30_000, unrestricted: 272_000 }),
|
|
335
|
+
max_output_tokens: 128_000,
|
|
256
336
|
cents_input: 125,
|
|
257
337
|
cents_output: 1000,
|
|
258
338
|
default_reasoning: true,
|
|
@@ -265,6 +345,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
265
345
|
llm_model_code: "gpt-5",
|
|
266
346
|
llm_api_code: "openai",
|
|
267
347
|
context_window: context_window_openai({ tier1: 30_000, unrestricted: 272_000 }),
|
|
348
|
+
max_output_tokens: 128_000,
|
|
268
349
|
cents_input: 125,
|
|
269
350
|
cents_output: 1000,
|
|
270
351
|
default_reasoning: false,
|
|
@@ -277,6 +358,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
277
358
|
llm_model_code: "gpt-5-mini",
|
|
278
359
|
llm_api_code: "openai",
|
|
279
360
|
context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
|
|
361
|
+
max_output_tokens: 128_000,
|
|
280
362
|
cents_input: 25,
|
|
281
363
|
cents_output: 200,
|
|
282
364
|
default_reasoning: true,
|
|
@@ -289,6 +371,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
289
371
|
llm_model_code: "gpt-5-mini",
|
|
290
372
|
llm_api_code: "openai",
|
|
291
373
|
context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
|
|
374
|
+
max_output_tokens: 128_000,
|
|
292
375
|
cents_input: 25,
|
|
293
376
|
cents_output: 200,
|
|
294
377
|
default_reasoning: true,
|
|
@@ -301,6 +384,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
301
384
|
llm_model_code: "gpt-5-mini",
|
|
302
385
|
llm_api_code: "openai",
|
|
303
386
|
context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
|
|
387
|
+
max_output_tokens: 128_000,
|
|
304
388
|
cents_input: 25,
|
|
305
389
|
cents_output: 200,
|
|
306
390
|
default_reasoning: true,
|
|
@@ -313,6 +397,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
313
397
|
llm_model_code: "gpt-5-mini",
|
|
314
398
|
llm_api_code: "openai",
|
|
315
399
|
context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
|
|
400
|
+
max_output_tokens: 128_000,
|
|
316
401
|
cents_input: 25,
|
|
317
402
|
cents_output: 200,
|
|
318
403
|
default_reasoning: true,
|
|
@@ -325,6 +410,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
325
410
|
llm_model_code: "gpt-5-mini",
|
|
326
411
|
llm_api_code: "openai",
|
|
327
412
|
context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
|
|
413
|
+
max_output_tokens: 128_000,
|
|
328
414
|
cents_input: 25,
|
|
329
415
|
cents_output: 200,
|
|
330
416
|
default_reasoning: false,
|
|
@@ -337,6 +423,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
337
423
|
llm_model_code: "gpt-5-nano",
|
|
338
424
|
llm_api_code: "openai",
|
|
339
425
|
context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
|
|
426
|
+
max_output_tokens: 128_000,
|
|
340
427
|
cents_input: 5,
|
|
341
428
|
cents_output: 40,
|
|
342
429
|
default_reasoning: true,
|
|
@@ -349,6 +436,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
349
436
|
llm_model_code: "gpt-5-nano",
|
|
350
437
|
llm_api_code: "openai",
|
|
351
438
|
context_window: context_window_openai({ tier1: 200_000, unrestricted: 272_000 }),
|
|
439
|
+
max_output_tokens: 128_000,
|
|
352
440
|
cents_input: 5,
|
|
353
441
|
cents_output: 40,
|
|
354
442
|
default_reasoning: false,
|
|
@@ -361,6 +449,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
361
449
|
llm_model_code: "openai/gpt-oss-120b",
|
|
362
450
|
llm_api_code: "openrouter",
|
|
363
451
|
context_window: 131_072,
|
|
452
|
+
max_output_tokens: 32_768,
|
|
364
453
|
cents_input: 25,
|
|
365
454
|
cents_output: 69,
|
|
366
455
|
default_reasoning: false,
|
|
@@ -373,6 +462,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
373
462
|
llm_model_code: "openai/gpt-oss-120b",
|
|
374
463
|
llm_api_code: "openrouter",
|
|
375
464
|
context_window: 131_072,
|
|
465
|
+
max_output_tokens: 65_536,
|
|
376
466
|
cents_input: 15,
|
|
377
467
|
cents_output: 75,
|
|
378
468
|
default_reasoning: false,
|
|
@@ -385,6 +475,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
385
475
|
llm_model_code: "x-ai/grok-3",
|
|
386
476
|
llm_api_code: "openrouter",
|
|
387
477
|
context_window: 131_072,
|
|
478
|
+
max_output_tokens: 131_072,
|
|
388
479
|
cents_input: 300,
|
|
389
480
|
cents_output: 1500,
|
|
390
481
|
default_reasoning: true,
|
|
@@ -397,6 +488,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
397
488
|
llm_model_code: "x-ai/grok-3-mini",
|
|
398
489
|
llm_api_code: "openrouter",
|
|
399
490
|
context_window: 131_072,
|
|
491
|
+
max_output_tokens: 131_072,
|
|
400
492
|
cents_input: 30,
|
|
401
493
|
cents_output: 50,
|
|
402
494
|
default_reasoning: true,
|
|
@@ -404,47 +496,51 @@ export const LLM_MODEL_DETAILS = [
|
|
|
404
496
|
recommended_temperature: undefined,
|
|
405
497
|
provider_options: undefined,
|
|
406
498
|
},
|
|
407
|
-
// {
|
|
408
|
-
// llm_model_name: "grok-4",
|
|
409
|
-
// llm_model_code: "x-ai/grok-4", // BYOK required
|
|
410
|
-
// llm_api_code: "openrouter",
|
|
411
|
-
// context_window: 256_000,
|
|
412
|
-
// cents_input: 300,
|
|
413
|
-
// cents_output: 1500,
|
|
414
|
-
// default_reasoning: true,
|
|
415
|
-
// has_structured_json: true,
|
|
416
|
-
// recommended_temperature: undefined,
|
|
417
|
-
// provider_options: undefined,
|
|
418
|
-
// },
|
|
419
499
|
{
|
|
420
|
-
llm_model_name: "grok-
|
|
421
|
-
llm_model_code: "x-ai/grok-
|
|
500
|
+
llm_model_name: "grok-4",
|
|
501
|
+
llm_model_code: "x-ai/grok-4",
|
|
422
502
|
llm_api_code: "openrouter",
|
|
423
503
|
context_window: 256_000,
|
|
424
|
-
|
|
425
|
-
|
|
504
|
+
max_output_tokens: 256_000,
|
|
505
|
+
cents_input: 300,
|
|
506
|
+
cents_output: 1500,
|
|
426
507
|
default_reasoning: true,
|
|
427
508
|
has_structured_json: true,
|
|
428
509
|
recommended_temperature: undefined,
|
|
429
510
|
provider_options: undefined,
|
|
430
511
|
},
|
|
431
512
|
{
|
|
432
|
-
llm_model_name: "
|
|
433
|
-
llm_model_code: "
|
|
513
|
+
llm_model_name: "grok-4-fast",
|
|
514
|
+
llm_model_code: "x-ai/grok-4-fast",
|
|
434
515
|
llm_api_code: "openrouter",
|
|
435
|
-
context_window:
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
516
|
+
context_window: 2_000_000,
|
|
517
|
+
max_output_tokens: 30_000,
|
|
518
|
+
cents_input: 20, // for input tokens <= 128K
|
|
519
|
+
cents_output: 50, // for input tokens <= 128K
|
|
520
|
+
default_reasoning: true,
|
|
521
|
+
has_structured_json: true,
|
|
440
522
|
recommended_temperature: undefined,
|
|
441
|
-
provider_options:
|
|
523
|
+
provider_options: undefined,
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
llm_model_name: "grok-code-fast-1",
|
|
527
|
+
llm_model_code: "x-ai/grok-code-fast-1",
|
|
528
|
+
llm_api_code: "openrouter",
|
|
529
|
+
context_window: 256_000,
|
|
530
|
+
max_output_tokens: 10_000,
|
|
531
|
+
cents_input: 20,
|
|
532
|
+
cents_output: 150,
|
|
533
|
+
default_reasoning: true,
|
|
534
|
+
has_structured_json: true,
|
|
535
|
+
recommended_temperature: undefined,
|
|
536
|
+
provider_options: undefined,
|
|
442
537
|
},
|
|
443
538
|
{
|
|
444
539
|
llm_model_name: "kimi-k2-0711@moonshotai",
|
|
445
540
|
llm_model_code: "moonshotai/kimi-k2",
|
|
446
541
|
llm_api_code: "openrouter",
|
|
447
542
|
context_window: 131_072,
|
|
543
|
+
max_output_tokens: 131_072,
|
|
448
544
|
cents_input: 60,
|
|
449
545
|
cents_output: 250,
|
|
450
546
|
default_reasoning: false,
|
|
@@ -457,6 +553,7 @@ export const LLM_MODEL_DETAILS = [
|
|
|
457
553
|
llm_model_code: "moonshotai/kimi-k2-0905",
|
|
458
554
|
llm_api_code: "openrouter",
|
|
459
555
|
context_window: 262_144,
|
|
556
|
+
max_output_tokens: 16_384,
|
|
460
557
|
cents_input: 100,
|
|
461
558
|
cents_output: 300,
|
|
462
559
|
default_reasoning: false,
|
|
@@ -465,34 +562,50 @@ export const LLM_MODEL_DETAILS = [
|
|
|
465
562
|
provider_options: provider_options_openrouter({ only: "groq" }),
|
|
466
563
|
},
|
|
467
564
|
{
|
|
468
|
-
llm_model_name: "llama-4-maverick@
|
|
565
|
+
llm_model_name: "llama-4-maverick@groq",
|
|
469
566
|
llm_model_code: "meta-llama/llama-4-maverick",
|
|
470
567
|
llm_api_code: "openrouter",
|
|
471
|
-
context_window:
|
|
568
|
+
context_window: 131_072,
|
|
569
|
+
max_output_tokens: 8192,
|
|
472
570
|
cents_input: 20,
|
|
473
571
|
cents_output: 60,
|
|
474
572
|
default_reasoning: false,
|
|
475
573
|
has_structured_json: true,
|
|
476
574
|
recommended_temperature: undefined,
|
|
477
|
-
provider_options: provider_options_openrouter({ only: "
|
|
575
|
+
provider_options: provider_options_openrouter({ only: "groq" }),
|
|
478
576
|
},
|
|
479
577
|
{
|
|
480
|
-
llm_model_name: "llama-4-scout@
|
|
578
|
+
llm_model_name: "llama-4-scout@groq",
|
|
481
579
|
llm_model_code: "meta-llama/llama-4-scout",
|
|
482
580
|
llm_api_code: "openrouter",
|
|
483
|
-
context_window:
|
|
484
|
-
|
|
485
|
-
|
|
581
|
+
context_window: 131_072,
|
|
582
|
+
max_output_tokens: 8192,
|
|
583
|
+
cents_input: 11,
|
|
584
|
+
cents_output: 34,
|
|
486
585
|
default_reasoning: false,
|
|
487
586
|
has_structured_json: true,
|
|
488
587
|
recommended_temperature: undefined,
|
|
489
|
-
provider_options: provider_options_openrouter({ only: "
|
|
588
|
+
provider_options: provider_options_openrouter({ only: "groq" }),
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
llm_model_name: "longcat-flash",
|
|
592
|
+
llm_model_code: "meituan/longcat-flash-chat",
|
|
593
|
+
llm_api_code: "openrouter",
|
|
594
|
+
context_window: 131_072,
|
|
595
|
+
max_output_tokens: 131_072,
|
|
596
|
+
cents_input: 15,
|
|
597
|
+
cents_output: 75,
|
|
598
|
+
default_reasoning: false,
|
|
599
|
+
has_structured_json: true,
|
|
600
|
+
recommended_temperature: undefined,
|
|
601
|
+
provider_options: undefined,
|
|
490
602
|
},
|
|
491
603
|
{
|
|
492
604
|
llm_model_name: "mercury",
|
|
493
605
|
llm_model_code: "inception/mercury",
|
|
494
606
|
llm_api_code: "openrouter",
|
|
495
|
-
context_window:
|
|
607
|
+
context_window: 128_000,
|
|
608
|
+
max_output_tokens: 16_384,
|
|
496
609
|
cents_input: 25,
|
|
497
610
|
cents_output: 100,
|
|
498
611
|
default_reasoning: false,
|
|
@@ -504,7 +617,8 @@ export const LLM_MODEL_DETAILS = [
|
|
|
504
617
|
llm_model_name: "mercury-coder",
|
|
505
618
|
llm_model_code: "inception/mercury-coder-small-beta",
|
|
506
619
|
llm_api_code: "openrouter",
|
|
507
|
-
context_window:
|
|
620
|
+
context_window: 128_000,
|
|
621
|
+
max_output_tokens: 16_384,
|
|
508
622
|
cents_input: 25,
|
|
509
623
|
cents_output: 100,
|
|
510
624
|
default_reasoning: false,
|
|
@@ -516,7 +630,8 @@ export const LLM_MODEL_DETAILS = [
|
|
|
516
630
|
llm_model_name: "mistral-medium-3.1",
|
|
517
631
|
llm_model_code: "mistralai/mistral-medium-3.1",
|
|
518
632
|
llm_api_code: "openrouter",
|
|
519
|
-
context_window:
|
|
633
|
+
context_window: 131_072,
|
|
634
|
+
max_output_tokens: 131_072,
|
|
520
635
|
cents_input: 40,
|
|
521
636
|
cents_output: 200,
|
|
522
637
|
default_reasoning: false,
|
|
@@ -528,7 +643,8 @@ export const LLM_MODEL_DETAILS = [
|
|
|
528
643
|
llm_model_name: "qwen3-235b-a22b-2507-instruct@cerebras",
|
|
529
644
|
llm_model_code: "qwen/qwen3-235b-a22b-2507",
|
|
530
645
|
llm_api_code: "openrouter",
|
|
531
|
-
context_window:
|
|
646
|
+
context_window: 131_072,
|
|
647
|
+
max_output_tokens: 131_072,
|
|
532
648
|
cents_input: 60,
|
|
533
649
|
cents_output: 120,
|
|
534
650
|
default_reasoning: false,
|
|
@@ -536,41 +652,31 @@ export const LLM_MODEL_DETAILS = [
|
|
|
536
652
|
recommended_temperature: undefined,
|
|
537
653
|
provider_options: provider_options_openrouter({ only: "cerebras" }),
|
|
538
654
|
},
|
|
539
|
-
{
|
|
540
|
-
llm_model_name: "qwen3-235b-a22b-2507-thinking@cerebras",
|
|
541
|
-
llm_model_code: "qwen/qwen3-235b-a22b-thinking-2507",
|
|
542
|
-
llm_api_code: "openrouter",
|
|
543
|
-
context_window: 262_144,
|
|
544
|
-
cents_input: 60,
|
|
545
|
-
cents_output: 120,
|
|
546
|
-
default_reasoning: true,
|
|
547
|
-
has_structured_json: true,
|
|
548
|
-
recommended_temperature: undefined,
|
|
549
|
-
provider_options: provider_options_openrouter({ only: "cerebras" }),
|
|
550
|
-
},
|
|
551
655
|
{
|
|
552
656
|
llm_model_name: "qwen3-coder@alibaba",
|
|
553
657
|
llm_model_code: "qwen/qwen3-coder",
|
|
554
658
|
llm_api_code: "openrouter",
|
|
555
659
|
context_window: 262_144,
|
|
556
|
-
|
|
557
|
-
|
|
660
|
+
max_output_tokens: 65_536,
|
|
661
|
+
cents_input: 150, // for input tokens <= 128K
|
|
662
|
+
cents_output: 750, // for input tokens <= 128K
|
|
558
663
|
default_reasoning: false,
|
|
559
664
|
has_structured_json: true,
|
|
560
665
|
recommended_temperature: undefined,
|
|
561
666
|
provider_options: provider_options_openrouter({ only: "alibaba/opensource" }),
|
|
562
667
|
},
|
|
563
668
|
{
|
|
564
|
-
llm_model_name: "
|
|
565
|
-
llm_model_code: "qwen/
|
|
669
|
+
llm_model_name: "qwen-plus@alibaba",
|
|
670
|
+
llm_model_code: "qwen/qwen-plus-2025-07-28",
|
|
566
671
|
llm_api_code: "openrouter",
|
|
567
|
-
context_window:
|
|
568
|
-
|
|
569
|
-
|
|
672
|
+
context_window: 1_000_000,
|
|
673
|
+
max_output_tokens: 32_768,
|
|
674
|
+
cents_input: 40, // for input tokens <= 256K
|
|
675
|
+
cents_output: 120, // for input tokens <= 256K
|
|
570
676
|
default_reasoning: false,
|
|
571
677
|
has_structured_json: true,
|
|
572
678
|
recommended_temperature: undefined,
|
|
573
|
-
provider_options: provider_options_openrouter({ only: "
|
|
679
|
+
provider_options: provider_options_openrouter({ only: "alibaba" }),
|
|
574
680
|
},
|
|
575
681
|
];
|
|
576
682
|
export function llm_model_get_details({ llm_model_names, }) {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { anyOf, createRegExp, digit, exactly, global, letter, oneOrMore, wordChar } from "magic-regexp";
|
|
2
|
+
import { ansi_yellow } from "./lib_ansi.js";
|
|
3
|
+
import { DASH } from "./lib_char_punctuation.js";
|
|
4
|
+
import { text_split_lines } from "./lib_text.js";
|
|
5
|
+
import { tui_confirm } from "./lib_tui_confirm.js";
|
|
6
|
+
import { tui_quote_smart_single } from "./lib_tui_quote.js";
|
|
7
|
+
const regexp_word_global = createRegExp(oneOrMore(anyOf(wordChar, exactly(DASH))), [global]);
|
|
8
|
+
const regexp_segment_global = createRegExp(oneOrMore(anyOf(letter, digit)), [global]);
|
|
9
|
+
const regexp_identifier_exactly = createRegExp(anyOf(
|
|
10
|
+
// Only letters (no digits)
|
|
11
|
+
oneOrMore(letter),
|
|
12
|
+
// Digits at the end
|
|
13
|
+
oneOrMore(letter).and(oneOrMore(digit)),
|
|
14
|
+
// Digits in the middle (letters before and after)
|
|
15
|
+
oneOrMore(letter)
|
|
16
|
+
.and(oneOrMore(digit))
|
|
17
|
+
.and(oneOrMore(letter)),
|
|
18
|
+
// Only digits (no letters)
|
|
19
|
+
oneOrMore(digit))
|
|
20
|
+
.at.lineStart()
|
|
21
|
+
.at.lineEnd());
|
|
22
|
+
function is_secret_line(line) {
|
|
23
|
+
if (line.endsWith(" # secret") || line.endsWith(" // secret")) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
const NOT_SECRET_LINE_INCLUDES = ["http://", "https://"];
|
|
29
|
+
function is_not_secret_line(line) {
|
|
30
|
+
if (line.endsWith(" not secret")) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
for (const not_secret_line_include of NOT_SECRET_LINE_INCLUDES) {
|
|
34
|
+
if (line.includes(not_secret_line_include)) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const SECRET_WORD_REGEXPS = [
|
|
41
|
+
/^ghp_[A-Za-z0-9]{30}/, // GitHub Personal Access Token
|
|
42
|
+
/^glpat-[A-Za-z0-9]{20}/, // GitLab Personal Access Token
|
|
43
|
+
/^sk-[A-Za-z0-9-]{30}/, // Secret Key
|
|
44
|
+
/^sk_[A-Za-z0-9]{30}/, // Secret Key
|
|
45
|
+
/^sk_test_[A-Za-z0-9]{30}/, // Secret Key (test)
|
|
46
|
+
/^whsec_[A-Za-z0-9]{30}/, // WebHook Secret key
|
|
47
|
+
/^xox[a-z]-[A-Za-z0-9-]{27}/, // Slack Access Token
|
|
48
|
+
];
|
|
49
|
+
function is_secret_word(word) {
|
|
50
|
+
for (const secret_word_regexp of SECRET_WORD_REGEXPS) {
|
|
51
|
+
if (secret_word_regexp.test(word)) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
async function is_secret_segment(segment, not_secret_segments, interactive) {
|
|
58
|
+
if (not_secret_segments.has(segment)) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
if (regexp_identifier_exactly.test(segment)) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
if (segment.length < 20) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
if (interactive) {
|
|
68
|
+
const confirmed_is_secret = await tui_confirm({
|
|
69
|
+
question: `Is ${tui_quote_smart_single(segment)} a secret?`,
|
|
70
|
+
default: false,
|
|
71
|
+
style_message: ansi_yellow,
|
|
72
|
+
});
|
|
73
|
+
if (!confirmed_is_secret) {
|
|
74
|
+
not_secret_segments.add(segment);
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
export async function secret_check({ text, interactive }) {
|
|
81
|
+
const not_secret_segments = new Set();
|
|
82
|
+
const lines = text_split_lines(text);
|
|
83
|
+
for (const line of lines.toReversed()) {
|
|
84
|
+
if (is_secret_line(line)) {
|
|
85
|
+
throw new Error(`Secret detected: ${tui_quote_smart_single(line.trim())}`);
|
|
86
|
+
}
|
|
87
|
+
const words = line.match(regexp_word_global);
|
|
88
|
+
const segments = line.match(regexp_segment_global);
|
|
89
|
+
if (!words || !segments) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (is_not_secret_line(line)) {
|
|
93
|
+
for (const segment of segments) {
|
|
94
|
+
not_secret_segments.add(segment);
|
|
95
|
+
}
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
for (const word of words) {
|
|
99
|
+
if (is_secret_word(word)) {
|
|
100
|
+
throw new Error(`Secret detected: ${tui_quote_smart_single(word)}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
for (const segment of segments) {
|
|
104
|
+
if (await is_secret_segment(segment, not_secret_segments, interactive)) {
|
|
105
|
+
throw new Error(`Secret detected: ${tui_quote_smart_single(segment)}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { LF } from "./lib_char_control.js";
|
|
2
|
+
import { EMPTY } from "./lib_char_empty.js";
|
|
3
|
+
export function text_split_lines(text) {
|
|
4
|
+
const lines = text.split(/\r?\n/);
|
|
5
|
+
if (lines.length > 0) {
|
|
6
|
+
const last_line = lines.at(-1);
|
|
7
|
+
if (last_line === EMPTY) {
|
|
8
|
+
return lines.slice(0, -1);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return lines;
|
|
12
|
+
}
|
|
13
|
+
export function text_join_lines(lines) {
|
|
14
|
+
return lines.length > 0 ? lines.join(LF) + LF : EMPTY;
|
|
15
|
+
}
|
|
16
|
+
function text_lines_matching_generic(text, pattern, remove) {
|
|
17
|
+
const regex = new RegExp(pattern);
|
|
18
|
+
const lines = text_split_lines(text);
|
|
19
|
+
const new_lines = [];
|
|
20
|
+
for (const line of lines) {
|
|
21
|
+
const found = regex.test(line);
|
|
22
|
+
if (found !== remove) {
|
|
23
|
+
new_lines.push(line);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return text_join_lines(new_lines);
|
|
27
|
+
}
|
|
28
|
+
export function text_lines_matching_only(text, pattern) {
|
|
29
|
+
return text_lines_matching_generic(text, pattern, false);
|
|
30
|
+
}
|
|
31
|
+
export function text_lines_matching_remove(text, pattern) {
|
|
32
|
+
return text_lines_matching_generic(text, pattern, true);
|
|
33
|
+
}
|
|
34
|
+
export function text_get_head(text, lines) {
|
|
35
|
+
return text_join_lines(text_split_lines(text).slice(0, lines));
|
|
36
|
+
}
|
|
37
|
+
export function text_get_tail(text, lines) {
|
|
38
|
+
return text_join_lines(text_split_lines(text).slice(-lines));
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnowennixon/diffdash",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.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",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/johnowennixon/diffdash.git"
|
|
9
|
+
"url": "git+https://github.com/johnowennixon/diffdash.git"
|
|
10
10
|
},
|
|
11
11
|
"engines": {
|
|
12
12
|
"node": ">=20"
|
|
@@ -19,34 +19,35 @@
|
|
|
19
19
|
"diffdash": "dist/src/diffdash.js"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@ai-sdk/anthropic": "2.0.
|
|
23
|
-
"@ai-sdk/deepseek": "1.0.
|
|
24
|
-
"@ai-sdk/google": "2.0.
|
|
25
|
-
"@ai-sdk/openai": "2.0.
|
|
26
|
-
"@inquirer/prompts": "
|
|
27
|
-
"@openrouter/ai-sdk-provider": "1.
|
|
28
|
-
"ai": "5.0.
|
|
29
|
-
"ansis": "4.
|
|
22
|
+
"@ai-sdk/anthropic": "2.0.53",
|
|
23
|
+
"@ai-sdk/deepseek": "1.0.31",
|
|
24
|
+
"@ai-sdk/google": "2.0.44",
|
|
25
|
+
"@ai-sdk/openai": "2.0.77",
|
|
26
|
+
"@inquirer/prompts": "8.0.2",
|
|
27
|
+
"@openrouter/ai-sdk-provider": "1.2.3",
|
|
28
|
+
"ai": "5.0.102",
|
|
29
|
+
"ansis": "4.2.0",
|
|
30
30
|
"argparse": "2.0.1",
|
|
31
31
|
"cli-table3": "0.6.5",
|
|
32
32
|
"json5": "2.2.3",
|
|
33
|
-
"
|
|
34
|
-
"
|
|
33
|
+
"magic-regexp": "0.10.0",
|
|
34
|
+
"simple-git": "3.30.0",
|
|
35
|
+
"zod": "4.1.13"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
37
|
-
"@biomejs/biome": "2.
|
|
38
|
-
"@candide/tsgolint": "1.
|
|
38
|
+
"@biomejs/biome": "2.3.8",
|
|
39
|
+
"@candide/tsgolint": "1.4.0",
|
|
39
40
|
"@johnowennixon/add-shebangs": "1.1.0",
|
|
40
41
|
"@johnowennixon/chmodx": "2.1.0",
|
|
41
42
|
"@types/argparse": "2.0.17",
|
|
42
|
-
"@types/node": "24.
|
|
43
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
44
|
-
"knip": "5.
|
|
45
|
-
"markdownlint-cli2": "0.
|
|
43
|
+
"@types/node": "24.10.1",
|
|
44
|
+
"@typescript/native-preview": "7.0.0-dev.20251022.1",
|
|
45
|
+
"knip": "5.71.0",
|
|
46
|
+
"markdownlint-cli2": "0.19.1",
|
|
46
47
|
"npm-run-all2": "8.0.4",
|
|
47
|
-
"oxlint": "1.
|
|
48
|
-
"rimraf": "6.
|
|
49
|
-
"typescript": "5.9.
|
|
48
|
+
"oxlint": "1.31.0",
|
|
49
|
+
"rimraf": "6.1.2",
|
|
50
|
+
"typescript": "5.9.3"
|
|
50
51
|
},
|
|
51
52
|
"scripts": {
|
|
52
53
|
"build": "run-s -ls build:clean build:tsc build:shebang build:chmod",
|