commit-whisper 1.0.6 → 1.0.8
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/dist/index.js +50 -23
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -163,6 +163,7 @@ function readProcessEnv() {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
// src/config/config-store.ts
|
|
166
|
+
import { randomBytes } from "crypto";
|
|
166
167
|
import { join } from "path";
|
|
167
168
|
import { mkdir, readFile, rename, unlink, writeFile } from "fs/promises";
|
|
168
169
|
var PROVIDERS2 = /* @__PURE__ */ new Set(["ollama", "openai", "gemini", "anthropic", "openai-compatible"]);
|
|
@@ -289,7 +290,7 @@ async function writeSettings(env, data, io = defaultConfigStoreIo) {
|
|
|
289
290
|
return finalPath;
|
|
290
291
|
}
|
|
291
292
|
function randomSuffix() {
|
|
292
|
-
return
|
|
293
|
+
return randomBytes(6).toString("hex");
|
|
293
294
|
}
|
|
294
295
|
|
|
295
296
|
// src/config/sources.ts
|
|
@@ -493,6 +494,15 @@ function resolveRunConfig(input) {
|
|
|
493
494
|
});
|
|
494
495
|
}
|
|
495
496
|
|
|
497
|
+
// src/shared/url.ts
|
|
498
|
+
function stripTrailingSlashes(value) {
|
|
499
|
+
let end = value.length;
|
|
500
|
+
while (end > 0 && value.codePointAt(end - 1) === 47) {
|
|
501
|
+
end -= 1;
|
|
502
|
+
}
|
|
503
|
+
return value.slice(0, end);
|
|
504
|
+
}
|
|
505
|
+
|
|
496
506
|
// src/narrate/preflight.ts
|
|
497
507
|
var OLLAMA_DEFAULT_BASE_URL = "http://localhost:11434";
|
|
498
508
|
var GEMINI_MODELS_URL = "https://generativelanguage.googleapis.com/v1beta/models";
|
|
@@ -528,7 +538,7 @@ function cleanBaseUrl(baseUrl) {
|
|
|
528
538
|
if (baseUrl === void 0) {
|
|
529
539
|
return void 0;
|
|
530
540
|
}
|
|
531
|
-
const trimmed = baseUrl.trim()
|
|
541
|
+
const trimmed = stripTrailingSlashes(baseUrl.trim());
|
|
532
542
|
return trimmed === "" ? void 0 : trimmed;
|
|
533
543
|
}
|
|
534
544
|
function classifyModelsResponse(res, providerLabel) {
|
|
@@ -765,7 +775,7 @@ function mapValidate(json) {
|
|
|
765
775
|
function resolveClient(deps) {
|
|
766
776
|
return {
|
|
767
777
|
doFetch: deps.fetchImpl ?? fetch,
|
|
768
|
-
apiBase: (deps.apiBase ?? DEFAULT_API_BASE)
|
|
778
|
+
apiBase: stripTrailingSlashes(deps.apiBase ?? DEFAULT_API_BASE),
|
|
769
779
|
timeoutMs: deps.timeoutMs ?? DEFAULT_TIMEOUT_MS2
|
|
770
780
|
};
|
|
771
781
|
}
|
|
@@ -815,6 +825,7 @@ function createLemonSqueezyDeactivator(deps = {}) {
|
|
|
815
825
|
}
|
|
816
826
|
|
|
817
827
|
// src/license/store.ts
|
|
828
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
818
829
|
import { join as join2 } from "path";
|
|
819
830
|
import { mkdir as mkdir2, readFile as readFile2, rename as rename2, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
|
|
820
831
|
var LICENSE_FILE_NAME = "license.json";
|
|
@@ -902,7 +913,7 @@ async function clearLicenseCache(env, io = defaultLicenseStoreIo) {
|
|
|
902
913
|
await io.unlink(licenseFilePath(env));
|
|
903
914
|
}
|
|
904
915
|
function randomSuffix2() {
|
|
905
|
-
return
|
|
916
|
+
return randomBytes2(6).toString("hex");
|
|
906
917
|
}
|
|
907
918
|
|
|
908
919
|
// src/retrieve/git.ts
|
|
@@ -1185,7 +1196,8 @@ function quoteArg(value) {
|
|
|
1185
1196
|
if (value !== "" && /^[A-Za-z0-9_./:@%+=-]+$/.test(value)) {
|
|
1186
1197
|
return value;
|
|
1187
1198
|
}
|
|
1188
|
-
|
|
1199
|
+
const escaped = value.replaceAll("'", String.raw`'\''`);
|
|
1200
|
+
return `'${escaped}'`;
|
|
1189
1201
|
}
|
|
1190
1202
|
function interpretLimit(raw) {
|
|
1191
1203
|
const trimmed = raw.trim();
|
|
@@ -1821,10 +1833,10 @@ function pad(n, width) {
|
|
|
1821
1833
|
// src/analyze/groups/a-cadence.ts
|
|
1822
1834
|
var DORMANT_GAP_SECONDS = 14 * 24 * 3600;
|
|
1823
1835
|
function minOf(values) {
|
|
1824
|
-
return values.reduce((m, v) => v
|
|
1836
|
+
return values.reduce((m, v) => Math.min(v, m), values[0]);
|
|
1825
1837
|
}
|
|
1826
1838
|
function maxOf(values) {
|
|
1827
|
-
return values.reduce((m, v) => v
|
|
1839
|
+
return values.reduce((m, v) => Math.max(v, m), values[0]);
|
|
1828
1840
|
}
|
|
1829
1841
|
var VOLUME = { id: "a-commit-volume", group: "A", title: "Commit volume over time" };
|
|
1830
1842
|
var CADENCE = { id: "a-commit-cadence", group: "A", title: "Commit frequency / cadence" };
|
|
@@ -2097,7 +2109,7 @@ var ownershipByArea = (model) => {
|
|
|
2097
2109
|
topFiles: topAreas(fileAreas, HOTSPOT_TOP_FILES)
|
|
2098
2110
|
});
|
|
2099
2111
|
};
|
|
2100
|
-
var CO_AUTHOR_TRAILER = /^[ \t]*co-authored-by:[ \t]*(
|
|
2112
|
+
var CO_AUTHOR_TRAILER = /^[ \t]*co-authored-by:[ \t]*(.+)$/gim;
|
|
2101
2113
|
function coAuthorKey(trailer) {
|
|
2102
2114
|
const angle = /<([^<>]+)>/.exec(trailer);
|
|
2103
2115
|
return (angle ? angle[1] : trailer).trim().toLowerCase();
|
|
@@ -2199,10 +2211,10 @@ function wordCount(text) {
|
|
|
2199
2211
|
return trimmed === "" ? 0 : trimmed.split(/\s+/).length;
|
|
2200
2212
|
}
|
|
2201
2213
|
function minOf2(values) {
|
|
2202
|
-
return values.length === 0 ? 0 : values.reduce((m, v) => v
|
|
2214
|
+
return values.length === 0 ? 0 : values.reduce((m, v) => Math.min(v, m), values[0]);
|
|
2203
2215
|
}
|
|
2204
2216
|
function maxOf3(values) {
|
|
2205
|
-
return values.length === 0 ? 0 : values.reduce((m, v) => v
|
|
2217
|
+
return values.length === 0 ? 0 : values.reduce((m, v) => Math.max(v, m), values[0]);
|
|
2206
2218
|
}
|
|
2207
2219
|
function sharePct(part, total) {
|
|
2208
2220
|
return total === 0 ? 0 : round(part / total * 100);
|
|
@@ -3528,7 +3540,11 @@ function resolveModel(config) {
|
|
|
3528
3540
|
return createOpenAICompatible({ name: "openai-compatible", baseURL, apiKey: config.aiKey?.reveal() })(model);
|
|
3529
3541
|
}
|
|
3530
3542
|
case "ollama": {
|
|
3531
|
-
|
|
3543
|
+
let base = cleanBaseUrl2(config.llmBaseUrl) ?? OLLAMA_DEFAULT_BASE_URL2;
|
|
3544
|
+
while (base.endsWith("/v1")) {
|
|
3545
|
+
base = base.slice(0, -3);
|
|
3546
|
+
}
|
|
3547
|
+
const baseURL = `${base}/v1`;
|
|
3532
3548
|
return createOpenAICompatible({ name: "ollama", baseURL })(model);
|
|
3533
3549
|
}
|
|
3534
3550
|
case void 0:
|
|
@@ -3564,7 +3580,7 @@ function cleanBaseUrl2(baseUrl) {
|
|
|
3564
3580
|
if (baseUrl === void 0) {
|
|
3565
3581
|
return void 0;
|
|
3566
3582
|
}
|
|
3567
|
-
const trimmed = baseUrl.trim()
|
|
3583
|
+
const trimmed = stripTrailingSlashes(baseUrl.trim());
|
|
3568
3584
|
return trimmed === "" ? void 0 : trimmed;
|
|
3569
3585
|
}
|
|
3570
3586
|
function assertNeverProvider(provider) {
|
|
@@ -4809,10 +4825,17 @@ function resolveNumstatPath(raw) {
|
|
|
4809
4825
|
if (!raw.includes(" => ")) {
|
|
4810
4826
|
return raw;
|
|
4811
4827
|
}
|
|
4812
|
-
const
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4828
|
+
const open2 = raw.indexOf("{");
|
|
4829
|
+
const close = open2 === -1 ? -1 : raw.indexOf("}", open2 + 1);
|
|
4830
|
+
if (open2 !== -1 && close !== -1) {
|
|
4831
|
+
const inside = raw.slice(open2 + 1, close);
|
|
4832
|
+
const arrow = inside.indexOf(" => ");
|
|
4833
|
+
if (arrow !== -1) {
|
|
4834
|
+
const prefix = raw.slice(0, open2);
|
|
4835
|
+
const next = inside.slice(arrow + " => ".length);
|
|
4836
|
+
const suffix = raw.slice(close + 1);
|
|
4837
|
+
return `${prefix}${next}${suffix}`.replace(/\/{2,}/g, "/");
|
|
4838
|
+
}
|
|
4816
4839
|
}
|
|
4817
4840
|
return raw.slice(raw.indexOf(" => ") + " => ".length);
|
|
4818
4841
|
}
|
|
@@ -5111,23 +5134,27 @@ async function runPipeline(config, deps = {}) {
|
|
|
5111
5134
|
const outcome = await narrateOutcome(config, narrateConfig, analysis, narrate, preflightReason);
|
|
5112
5135
|
const report = reportFromOutcome(analysis, outcome);
|
|
5113
5136
|
const targets = planOutputs(config.outputFormats, config.outputPath);
|
|
5137
|
+
const htmlFilePath = await emitOutputs(report, targets, { writeStdout: writeStdout2, writeFile: writeFile3, ui: ui2 });
|
|
5138
|
+
if (autoOpen && htmlFilePath !== void 0) {
|
|
5139
|
+
await tryOpen(openBrowser, htmlFilePath, ui2);
|
|
5140
|
+
}
|
|
5141
|
+
return report.degraded ? ExitCode.Degraded : ExitCode.Success;
|
|
5142
|
+
}
|
|
5143
|
+
async function emitOutputs(report, targets, io) {
|
|
5114
5144
|
let htmlFilePath;
|
|
5115
5145
|
for (const target of targets) {
|
|
5116
5146
|
const text = renderOne(report, target);
|
|
5117
5147
|
if (target.destination.kind === "stdout") {
|
|
5118
|
-
|
|
5148
|
+
io.writeStdout(text.endsWith("\n") ? text : `${text}
|
|
5119
5149
|
`);
|
|
5120
5150
|
} else {
|
|
5121
|
-
await writeOne(
|
|
5151
|
+
await writeOne(io.writeFile, target.destination.path, text, target.format, io.ui);
|
|
5122
5152
|
if (target.format === "html") {
|
|
5123
5153
|
htmlFilePath = target.destination.path;
|
|
5124
5154
|
}
|
|
5125
5155
|
}
|
|
5126
5156
|
}
|
|
5127
|
-
|
|
5128
|
-
await tryOpen(openBrowser, htmlFilePath, ui2);
|
|
5129
|
-
}
|
|
5130
|
-
return report.degraded ? ExitCode.Degraded : ExitCode.Success;
|
|
5157
|
+
return htmlFilePath;
|
|
5131
5158
|
}
|
|
5132
5159
|
function renderOne(report, target) {
|
|
5133
5160
|
try {
|
|
@@ -5237,7 +5264,7 @@ function formatShowConfig(config, secrets) {
|
|
|
5237
5264
|
}
|
|
5238
5265
|
|
|
5239
5266
|
// src/cli/version.ts
|
|
5240
|
-
var VERSION = "1.0.
|
|
5267
|
+
var VERSION = "1.0.8";
|
|
5241
5268
|
|
|
5242
5269
|
// src/cli/cli.ts
|
|
5243
5270
|
var PROVIDERS3 = ["ollama", "openai", "gemini", "anthropic", "openai-compatible"];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "commit-whisper",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Deterministic git history analysis with a grounded, BYOK AI narrative — terminal-native CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -45,24 +45,24 @@
|
|
|
45
45
|
},
|
|
46
46
|
"homepage": "https://github.com/georgiosnikitas/commit-whisper#readme",
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@ai-sdk/anthropic": "3.0.
|
|
49
|
-
"@ai-sdk/google": "3.0.
|
|
50
|
-
"@ai-sdk/openai": "3.0.
|
|
51
|
-
"@ai-sdk/openai-compatible": "2.0.
|
|
48
|
+
"@ai-sdk/anthropic": "3.0.85",
|
|
49
|
+
"@ai-sdk/google": "3.0.83",
|
|
50
|
+
"@ai-sdk/openai": "3.0.72",
|
|
51
|
+
"@ai-sdk/openai-compatible": "2.0.51",
|
|
52
52
|
"@clack/prompts": "1.5.1",
|
|
53
|
-
"ai": "6.0.
|
|
53
|
+
"ai": "6.0.207",
|
|
54
54
|
"commander": "15.0.0",
|
|
55
55
|
"picocolors": "1.1.1",
|
|
56
56
|
"zod": "4.4.3"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@types/node": "
|
|
60
|
-
"@vitest/coverage-v8": "4.1.
|
|
59
|
+
"@types/node": "25.9.3",
|
|
60
|
+
"@vitest/coverage-v8": "4.1.9",
|
|
61
61
|
"eslint": "10.5.0",
|
|
62
62
|
"tsup": "8.5.1",
|
|
63
63
|
"typescript": "6.0.3",
|
|
64
|
-
"typescript-eslint": "8.61.
|
|
65
|
-
"vitest": "4.1.
|
|
64
|
+
"typescript-eslint": "8.61.1",
|
|
65
|
+
"vitest": "4.1.9"
|
|
66
66
|
},
|
|
67
67
|
"overrides": {
|
|
68
68
|
"esbuild": "^0.28.1"
|