@johnowennixon/diffdash 1.6.1 → 1.8.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.
@@ -0,0 +1,47 @@
1
+ import { SPACE } from "./lib_char_punctuation.js";
2
+ import { tell_action, tell_info, tell_warning } from "./lib_tell.js";
3
+ import { tui_justify_left } from "./lib_tui_justify.js";
4
+ import { tui_none_blank } from "./lib_tui_none.js";
5
+ import { tui_number_plain } from "./lib_tui_number.js";
6
+ export function llm_results_summary(all_results) {
7
+ tell_action("Showing summary of responses ...");
8
+ all_results = all_results.toSorted((a, b) => a.seconds - b.seconds);
9
+ const max_length_model = Math.max(...all_results.map((result) => result.llm_config.llm_model_name.length));
10
+ for (const result of all_results) {
11
+ const { llm_config, seconds, error_text } = result;
12
+ if (error_text === null) {
13
+ continue;
14
+ }
15
+ const { llm_model_name } = llm_config;
16
+ const tui_model = tui_justify_left(max_length_model, llm_model_name);
17
+ const tui_seconds = tui_number_plain({ num: seconds, justify_left: 3 });
18
+ tell_warning(`${tui_model} seconds=${tui_seconds} ${error_text}`);
19
+ }
20
+ for (const result of all_results) {
21
+ const { llm_config, seconds, error_text } = result;
22
+ if (error_text !== null) {
23
+ continue;
24
+ }
25
+ const { llm_model_name } = llm_config;
26
+ const { outputs } = result;
27
+ const { total_usage, provider_metadata } = outputs;
28
+ const openrouter_provider = provider_metadata?.["openrouter"]?.["provider"];
29
+ const tui_model = tui_justify_left(max_length_model, llm_model_name);
30
+ const tui_seconds = tui_number_plain({ num: seconds, justify_left: 3 });
31
+ const tui_input = tui_number_plain({ num: total_usage.inputTokens, justify_left: 5 });
32
+ const tui_output = tui_number_plain({ num: total_usage.outputTokens, justify_left: 5 });
33
+ const tui_reasoning = tui_number_plain({ num: total_usage.reasoningTokens, justify_left: 5 });
34
+ const tui_provider = tui_none_blank(openrouter_provider);
35
+ const segments = [];
36
+ segments.push(tui_model);
37
+ segments.push(`seconds=${tui_seconds}`);
38
+ segments.push(`input=${tui_input}`);
39
+ segments.push(`output=${tui_output}`);
40
+ segments.push(`reasoning=${tui_reasoning}`);
41
+ if (openrouter_provider) {
42
+ segments.push(`provider=${tui_provider}`);
43
+ }
44
+ const message = segments.join(SPACE + SPACE);
45
+ tell_info(message);
46
+ }
47
+ }
@@ -2,12 +2,14 @@ import { ansi_cyan, ansi_green, ansi_grey, ansi_magenta, ansi_normal, ansi_red,
2
2
  import { LF } from "./lib_char_control.js";
3
3
  import { EMPTY } from "./lib_char_empty.js";
4
4
  import { SPACE } from "./lib_char_punctuation.js";
5
- import { datetime_format_local_iso_ymdthms, datetime_now } from "./lib_datetime.js";
5
+ import { datetime_format_local_iso_ymd_hms, datetime_now } from "./lib_datetime.js";
6
6
  import { enabled_from_env } from "./lib_enabled.js";
7
- import { stdio_write_stderr_linefeed } from "./lib_stdio_write.js";
7
+ import { stdio_write_stderr_linefeed, stdio_write_stdout_linefeed } from "./lib_stdio_write.js";
8
8
  export const tell_enables = {
9
- timestamp: enabled_from_env("TELL_TIMESTAMP"),
9
+ ansi: enabled_from_env("TELL_ANSI", { default: true }),
10
10
  okay: enabled_from_env("TELL_OKAY", { default: true }),
11
+ stdout: enabled_from_env("TELL_STDOUT"),
12
+ timestamp: enabled_from_env("TELL_TIMESTAMP"),
11
13
  };
12
14
  function tell_generic({ message, colourizer }) {
13
15
  while (message.endsWith(LF)) {
@@ -15,14 +17,13 @@ function tell_generic({ message, colourizer }) {
15
17
  }
16
18
  let text = EMPTY;
17
19
  if (tell_enables.timestamp) {
18
- const now_local_ymdthms = datetime_format_local_iso_ymdthms(datetime_now());
20
+ const now_local_ymdthms = datetime_format_local_iso_ymd_hms(datetime_now());
19
21
  text += ansi_grey(now_local_ymdthms);
20
- text += SPACE;
21
- }
22
- if (colourizer) {
23
- text += colourizer(message);
22
+ text += SPACE + SPACE;
24
23
  }
25
- stdio_write_stderr_linefeed(text);
24
+ text += tell_enables.ansi && colourizer ? colourizer(message) : message;
25
+ const teller = tell_enables.stdout ? stdio_write_stdout_linefeed : stdio_write_stderr_linefeed;
26
+ teller(text);
26
27
  }
27
28
  export function tell_nowhere(_message) {
28
29
  // intentionally empty
@@ -49,7 +50,7 @@ export function tell_debug(message) {
49
50
  tell_generic({ message, colourizer: ansi_grey });
50
51
  }
51
52
  export function tell_blank() {
52
- tell_plain(EMPTY);
53
+ tell_generic({ message: EMPTY });
53
54
  }
54
55
  export function tell_okay() {
55
56
  if (tell_enables.okay) {
@@ -0,0 +1,15 @@
1
+ import { EMPTY } from "./lib_char_empty.js";
2
+ import { DASH } from "./lib_char_punctuation.js";
3
+ // eslint-disable-next-line sonarjs/use-type-alias
4
+ function tui_none_generic(str, replacement) {
5
+ if (str === undefined || str === null || str === EMPTY) {
6
+ return replacement;
7
+ }
8
+ return str.toString();
9
+ }
10
+ export function tui_none_blank(str) {
11
+ return tui_none_generic(str, EMPTY);
12
+ }
13
+ export function tui_none_dash(str) {
14
+ return tui_none_generic(str, DASH);
15
+ }
@@ -0,0 +1,22 @@
1
+ import { EMPTY } from "./lib_char_empty.js";
2
+ import { DOT } from "./lib_char_punctuation.js";
3
+ import { tui_justify_left, tui_justify_zero } from "./lib_tui_justify.js";
4
+ export function tui_number_plain({ num, justify_left, justify_right, }) {
5
+ let str = num === null || num === undefined ? EMPTY : num.toString();
6
+ if (justify_left !== undefined) {
7
+ str = tui_justify_left(justify_left, str);
8
+ }
9
+ if (justify_right !== undefined) {
10
+ str = tui_justify_left(justify_right, str);
11
+ }
12
+ return str;
13
+ }
14
+ export function tui_number_integer_commas(n) {
15
+ return Math.round(n).toLocaleString();
16
+ }
17
+ export function tui_number_money_format(value) {
18
+ const rounded = Math.round(value * 100);
19
+ const units = Math.floor(rounded / 100);
20
+ const cents = rounded % 100;
21
+ return tui_number_integer_commas(units) + DOT + tui_justify_zero(2, cents.toString());
22
+ }
@@ -0,0 +1,26 @@
1
+ import { BACKTICK, LESS_THAN, MORE_THAN, QUOTE_DOUBLE, QUOTE_SINGLE, ROUND_LEFT, ROUND_RIGHT, SQUARE_LEFT, SQUARE_RIGHT, } from "./lib_char_punctuation.js";
2
+ import { LEFT_DOUBLE_QUOTATION_MARK, LEFT_SINGLE_QUOTATION_MARK, RIGHT_DOUBLE_QUOTATION_MARK, RIGHT_SINGLE_QUOTATION_MARK, } from "./lib_char_smart.js";
3
+ export function tui_quote_plain_double(s) {
4
+ return QUOTE_DOUBLE + s + QUOTE_DOUBLE;
5
+ }
6
+ export function tui_quote_plain_single(s) {
7
+ return QUOTE_SINGLE + s + QUOTE_SINGLE;
8
+ }
9
+ export function tui_quote_smart_double(s) {
10
+ return LEFT_DOUBLE_QUOTATION_MARK + s + RIGHT_DOUBLE_QUOTATION_MARK;
11
+ }
12
+ export function tui_quote_smart_single(s) {
13
+ return LEFT_SINGLE_QUOTATION_MARK + s + RIGHT_SINGLE_QUOTATION_MARK;
14
+ }
15
+ export function tui_quote_bracket_round(s) {
16
+ return ROUND_LEFT + s + ROUND_RIGHT;
17
+ }
18
+ export function tui_quote_bracket_square(s) {
19
+ return SQUARE_LEFT + s + SQUARE_RIGHT;
20
+ }
21
+ export function tui_quote_bracket_angle(s) {
22
+ return LESS_THAN + s + MORE_THAN;
23
+ }
24
+ export function tui_quote_backtick(s) {
25
+ return BACKTICK + s + BACKTICK;
26
+ }
@@ -1,18 +1,26 @@
1
1
  import cli_table3 from "cli-table3";
2
+ import { abort_with_error } from "./lib_abort.js";
2
3
  import { ansi_bold } from "./lib_ansi.js";
3
4
  export class TuiTable {
4
5
  table;
5
- count = 0;
6
- constructor({ headings }) {
6
+ columns_total;
7
+ constructor({ headings, alignments }) {
7
8
  const constructor_options = { style: { head: [] } };
8
- if (headings) {
9
- constructor_options.head = headings.map((heading) => ansi_bold(heading));
9
+ constructor_options.head = headings.map((heading) => ansi_bold(heading));
10
+ this.columns_total = headings.length;
11
+ if (alignments) {
12
+ if (alignments.length !== this.columns_total) {
13
+ abort_with_error(`length of alignments (${alignments.length}) must match length of headings (${this.columns_total})`);
14
+ }
15
+ constructor_options.colAligns = alignments;
10
16
  }
11
17
  this.table = new cli_table3(constructor_options);
12
18
  }
13
19
  push(row) {
20
+ if (row.length !== this.columns_total) {
21
+ abort_with_error(`length of row (${row.length}) must match length of headings (${this.columns_total})`);
22
+ }
14
23
  this.table.push(row);
15
- this.count++;
16
24
  }
17
25
  toString() {
18
26
  return this.table.toString();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@johnowennixon/diffdash",
3
- "version": "1.6.1",
3
+ "version": "1.8.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",
@@ -19,43 +19,33 @@
19
19
  "diffdash": "dist/src/diffdash.js"
20
20
  },
21
21
  "dependencies": {
22
- "@ai-sdk/anthropic": "1.2.12",
23
- "@ai-sdk/deepseek": "0.2.16",
24
- "@ai-sdk/google": "1.2.22",
25
- "@ai-sdk/openai": "1.3.23",
26
- "@openrouter/ai-sdk-provider": "0.7.2",
27
- "@requesty/ai-sdk": "0.0.9",
28
- "ai": "4.3.19",
22
+ "@ai-sdk/anthropic": "2.0.1",
23
+ "@ai-sdk/deepseek": "1.0.5",
24
+ "@ai-sdk/google": "2.0.4",
25
+ "@ai-sdk/openai": "2.0.9",
26
+ "@openrouter/ai-sdk-provider": "1.1.2",
27
+ "ai": "5.0.9",
29
28
  "ansis": "4.1.0",
30
29
  "argparse": "2.0.1",
31
30
  "cli-table3": "0.6.5",
31
+ "json5": "2.2.3",
32
32
  "simple-git": "3.28.0",
33
- "zod": "3.25.76"
33
+ "zod": "4.0.17"
34
34
  },
35
35
  "devDependencies": {
36
- "@biomejs/biome": "2.1.1",
37
- "@eslint/eslintrc": "3.3.1",
38
- "@eslint/js": "9.31.0",
36
+ "@biomejs/biome": "2.1.4",
37
+ "@candide/tsgolint": "1.3.0",
39
38
  "@johnowennixon/add-shebangs": "1.1.0",
40
39
  "@johnowennixon/chmodx": "2.0.0",
41
- "@stylistic/eslint-plugin": "5.2.0",
42
40
  "@types/argparse": "2.0.17",
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
- "eslint-import-resolver-typescript": "4.4.4",
48
- "eslint-plugin-import-x": "4.16.1",
49
- "eslint-plugin-sonarjs": "3.0.4",
50
- "eslint-plugin-unicorn": "59.0.1",
51
- "globals": "16.3.0",
52
- "knip": "5.61.3",
41
+ "@types/node": "24.2.1",
42
+ "@typescript/native-preview": "7.0.0-dev.20250811.1",
43
+ "knip": "5.62.0",
53
44
  "markdownlint-cli2": "0.18.1",
54
45
  "npm-run-all2": "8.0.4",
55
- "oxlint": "1.7.0",
46
+ "oxlint": "1.11.1",
56
47
  "rimraf": "6.0.1",
57
- "typescript": "5.8.3",
58
- "typescript-eslint": "8.37.0"
48
+ "typescript": "5.9.2"
59
49
  },
60
50
  "scripts": {
61
51
  "build": "run-s -ls build:clean build:tsc build:shebang build:chmod",
@@ -63,18 +53,21 @@
63
53
  "build:clean": "echo 'Removing dist' && rimraf dist",
64
54
  "build:shebang": "echo 'Fixing the shebangs' && add-shebangs --node --exclude 'dist/**/lib_*.js' 'dist/**/*.js'",
65
55
  "build:tsc": "echo 'Transpiling TypeScript to dist (using tsc)' && tsc --erasableSyntaxOnly --libReplacement false",
56
+ "build:tsgo": "echo 'Transpiling TypeScript to dist (using tsgo)' && tsgo || (rimraf dist && false)",
66
57
  "fix": "run-s -ls fix:biome fix:markdownlint",
67
58
  "fix:biome": "echo 'Fixing with Biome' && biome check --write",
68
- "fix:eslint": "echo 'Fixing with ESLint' && eslint --fix",
59
+ "fix:docbot": "echo 'Fixing with DocBot' && docbot --prune --generate",
69
60
  "fix:markdownlint": "echo 'Fixing with markdownlint' && markdownlint-cli2 '**/*.md' --fix",
70
- "fix:oxlint": "echo 'Fixing with oxlint' && oxlint --fix",
71
- "lint": "run-s -ls lint:biome lint:oxlint lint:knip lint:markdownlint",
61
+ "fix:oxlint": "echo 'Fixing with Oxlint' && oxlint --fix",
62
+ "lint": "run-s -ls lint:biome lint:oxlint lint:tsgolint lint:knip lint:markdownlint",
72
63
  "lint:biome": "echo 'Linting with Biome' && biome check",
73
- "lint:eslint": "echo 'Linting with ESLint' && eslint",
64
+ "lint:docbot": "echo 'Linting with DocBot' && docbot",
74
65
  "lint:knip": "echo 'Linting with Knip' && knip",
75
- "lint:markdownlint": "echo 'Linting with markdownlint' && markdownlint-cli2 '**/*.md'",
76
- "lint:oxlint": "echo 'Linting with oxlint' && oxlint",
66
+ "lint:markdownlint": "echo 'Linting with Markdownlint' && markdownlint-cli2 '**/*.md'",
67
+ "lint:oxlint": "echo 'Linting with Oxlint' && oxlint",
77
68
  "lint:tsc": "echo 'Linting with tsc' && tsc --noEmit --erasableSyntaxOnly --libReplacement false",
69
+ "lint:tsgo": "echo 'Linting with tsgo' && tsgo --noEmit",
70
+ "lint:tsgolint": "echo 'Linting with tsgolint' && candide-tsgolint",
78
71
  "test": "run-s -ls lint build"
79
72
  }
80
73
  }