commit-whisper 1.0.7 → 1.1.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/dist/index.js +1505 -439
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -145,24 +145,42 @@ function aiKeyEnvVar(provider) {
|
|
|
145
145
|
return "OPENAI_API_KEY";
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
var PROVIDER_KEY_VARS = [
|
|
149
|
+
{ provider: "openai", name: "OPENAI_API_KEY" },
|
|
150
|
+
{ provider: "anthropic", name: "ANTHROPIC_API_KEY" },
|
|
151
|
+
{ provider: "gemini", name: "GOOGLE_GENERATIVE_AI_API_KEY" }
|
|
152
|
+
];
|
|
153
|
+
function isActiveKeyRow(rowProvider, active) {
|
|
154
|
+
if (active === rowProvider) {
|
|
155
|
+
return true;
|
|
153
156
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
return active === "openai-compatible" && rowProvider === "openai";
|
|
158
|
+
}
|
|
159
|
+
function readEnvDiagnostics(env, provider) {
|
|
160
|
+
return [
|
|
161
|
+
...PROVIDER_KEY_VARS.map(({ provider: p, name }) => ({
|
|
162
|
+
name,
|
|
163
|
+
set: readAiKey(env, p) !== void 0,
|
|
164
|
+
note: isActiveKeyRow(p, provider) ? "active provider" : void 0
|
|
165
|
+
})),
|
|
166
|
+
{
|
|
167
|
+
name: "COMMIT_WHISPER_GIT_TOKEN",
|
|
168
|
+
set: readGitToken(env) !== void 0,
|
|
169
|
+
note: "only needed for private remotes"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: "COMMIT_WHISPER_LICENSE_KEY",
|
|
173
|
+
set: readLicenseKey(env) !== void 0,
|
|
174
|
+
note: "unlocks paid tiers when valid"
|
|
175
|
+
}
|
|
176
|
+
];
|
|
160
177
|
}
|
|
161
178
|
function readProcessEnv() {
|
|
162
179
|
return process.env;
|
|
163
180
|
}
|
|
164
181
|
|
|
165
182
|
// src/config/config-store.ts
|
|
183
|
+
import { randomBytes } from "crypto";
|
|
166
184
|
import { join } from "path";
|
|
167
185
|
import { mkdir, readFile, rename, unlink, writeFile } from "fs/promises";
|
|
168
186
|
var PROVIDERS2 = /* @__PURE__ */ new Set(["ollama", "openai", "gemini", "anthropic", "openai-compatible"]);
|
|
@@ -289,7 +307,7 @@ async function writeSettings(env, data, io = defaultConfigStoreIo) {
|
|
|
289
307
|
return finalPath;
|
|
290
308
|
}
|
|
291
309
|
function randomSuffix() {
|
|
292
|
-
return
|
|
310
|
+
return randomBytes(6).toString("hex");
|
|
293
311
|
}
|
|
294
312
|
|
|
295
313
|
// src/config/sources.ts
|
|
@@ -493,6 +511,15 @@ function resolveRunConfig(input) {
|
|
|
493
511
|
});
|
|
494
512
|
}
|
|
495
513
|
|
|
514
|
+
// src/shared/url.ts
|
|
515
|
+
function stripTrailingSlashes(value) {
|
|
516
|
+
let end = value.length;
|
|
517
|
+
while (end > 0 && value.codePointAt(end - 1) === 47) {
|
|
518
|
+
end -= 1;
|
|
519
|
+
}
|
|
520
|
+
return value.slice(0, end);
|
|
521
|
+
}
|
|
522
|
+
|
|
496
523
|
// src/narrate/preflight.ts
|
|
497
524
|
var OLLAMA_DEFAULT_BASE_URL = "http://localhost:11434";
|
|
498
525
|
var GEMINI_MODELS_URL = "https://generativelanguage.googleapis.com/v1beta/models";
|
|
@@ -528,7 +555,7 @@ function cleanBaseUrl(baseUrl) {
|
|
|
528
555
|
if (baseUrl === void 0) {
|
|
529
556
|
return void 0;
|
|
530
557
|
}
|
|
531
|
-
const trimmed = baseUrl.trim()
|
|
558
|
+
const trimmed = stripTrailingSlashes(baseUrl.trim());
|
|
532
559
|
return trimmed === "" ? void 0 : trimmed;
|
|
533
560
|
}
|
|
534
561
|
function classifyModelsResponse(res, providerLabel) {
|
|
@@ -650,11 +677,18 @@ function tierForVariantName(variantName) {
|
|
|
650
677
|
}
|
|
651
678
|
return "single-device";
|
|
652
679
|
}
|
|
680
|
+
function tierForLicense(input) {
|
|
681
|
+
const limit = input.activationLimit;
|
|
682
|
+
if (limit === void 0) {
|
|
683
|
+
return tierForVariantName(input.variantName);
|
|
684
|
+
}
|
|
685
|
+
return limit === 1 ? "single-device" : "unlimited";
|
|
686
|
+
}
|
|
653
687
|
function tierForValidation(v) {
|
|
654
688
|
if (!v.valid) {
|
|
655
689
|
return "free";
|
|
656
690
|
}
|
|
657
|
-
return
|
|
691
|
+
return tierForLicense({ variantName: v.variantName, activationLimit: v.activationLimit });
|
|
658
692
|
}
|
|
659
693
|
function entitlementForTier(tier) {
|
|
660
694
|
if (tier === "free") {
|
|
@@ -704,7 +738,7 @@ async function activateLicense(deps) {
|
|
|
704
738
|
reason: `Activated online, but couldn't save it on this device (${detail}). Set COMMIT_WHISPER_LICENSE_KEY so it applies on your next run \u2014 do NOT re-activate (that would use another device slot).`
|
|
705
739
|
};
|
|
706
740
|
}
|
|
707
|
-
return { ok: true, tier:
|
|
741
|
+
return { ok: true, tier: tierForLicense({ variantName: result.variantName, activationLimit: result.activationLimit }) };
|
|
708
742
|
}
|
|
709
743
|
async function deactivateLicense(deps) {
|
|
710
744
|
if (deps.licenseKey === void 0 || deps.licenseKey === "") {
|
|
@@ -765,7 +799,7 @@ function mapValidate(json) {
|
|
|
765
799
|
function resolveClient(deps) {
|
|
766
800
|
return {
|
|
767
801
|
doFetch: deps.fetchImpl ?? fetch,
|
|
768
|
-
apiBase: (deps.apiBase ?? DEFAULT_API_BASE)
|
|
802
|
+
apiBase: stripTrailingSlashes(deps.apiBase ?? DEFAULT_API_BASE),
|
|
769
803
|
timeoutMs: deps.timeoutMs ?? DEFAULT_TIMEOUT_MS2
|
|
770
804
|
};
|
|
771
805
|
}
|
|
@@ -797,6 +831,7 @@ function createLemonSqueezyActivator(deps = {}) {
|
|
|
797
831
|
instanceId: json.instance?.id,
|
|
798
832
|
variantName: json.meta?.variant_name,
|
|
799
833
|
variantId: json.meta?.variant_id,
|
|
834
|
+
activationLimit: json.license_key?.activation_limit,
|
|
800
835
|
error: json.error ?? void 0
|
|
801
836
|
};
|
|
802
837
|
};
|
|
@@ -815,6 +850,7 @@ function createLemonSqueezyDeactivator(deps = {}) {
|
|
|
815
850
|
}
|
|
816
851
|
|
|
817
852
|
// src/license/store.ts
|
|
853
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
818
854
|
import { join as join2 } from "path";
|
|
819
855
|
import { mkdir as mkdir2, readFile as readFile2, rename as rename2, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
|
|
820
856
|
var LICENSE_FILE_NAME = "license.json";
|
|
@@ -902,7 +938,7 @@ async function clearLicenseCache(env, io = defaultLicenseStoreIo) {
|
|
|
902
938
|
await io.unlink(licenseFilePath(env));
|
|
903
939
|
}
|
|
904
940
|
function randomSuffix2() {
|
|
905
|
-
return
|
|
941
|
+
return randomBytes2(6).toString("hex");
|
|
906
942
|
}
|
|
907
943
|
|
|
908
944
|
// src/retrieve/git.ts
|
|
@@ -1007,6 +1043,106 @@ function resolveColor(input) {
|
|
|
1007
1043
|
return input.isTTY;
|
|
1008
1044
|
}
|
|
1009
1045
|
var ui = createUi();
|
|
1046
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
1047
|
+
var SPINNER_INTERVAL_MS = 80;
|
|
1048
|
+
var CLEAR_LINE = "\r\x1B[2K";
|
|
1049
|
+
var noopProgress = {
|
|
1050
|
+
start() {
|
|
1051
|
+
},
|
|
1052
|
+
update() {
|
|
1053
|
+
},
|
|
1054
|
+
done() {
|
|
1055
|
+
},
|
|
1056
|
+
fail() {
|
|
1057
|
+
},
|
|
1058
|
+
clear() {
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
function createProgress(stream = process.stderr, opts = {}) {
|
|
1062
|
+
const level = opts.level ?? "normal";
|
|
1063
|
+
if (level === "quiet") {
|
|
1064
|
+
return noopProgress;
|
|
1065
|
+
}
|
|
1066
|
+
const colors = pc.createColors(opts.color ?? false);
|
|
1067
|
+
const animate = opts.tty === true;
|
|
1068
|
+
const total = opts.total;
|
|
1069
|
+
let label = "";
|
|
1070
|
+
let step = 0;
|
|
1071
|
+
let frame = 0;
|
|
1072
|
+
let active = false;
|
|
1073
|
+
let timer;
|
|
1074
|
+
const counter = () => total === void 0 ? "" : `[${Math.min(step, total)}/${total}] `;
|
|
1075
|
+
const render = () => {
|
|
1076
|
+
const spinner = colors.cyan(SPINNER_FRAMES[frame % SPINNER_FRAMES.length]);
|
|
1077
|
+
stream.write(`${CLEAR_LINE}${spinner} ${counter()}${label}`);
|
|
1078
|
+
};
|
|
1079
|
+
const stopTimer = () => {
|
|
1080
|
+
if (timer !== void 0) {
|
|
1081
|
+
clearInterval(timer);
|
|
1082
|
+
timer = void 0;
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
const finish = (symbol, finalLabel) => {
|
|
1086
|
+
if (!active) {
|
|
1087
|
+
if (finalLabel !== void 0) {
|
|
1088
|
+
stream.write(`${symbol} ${counter()}${finalLabel}
|
|
1089
|
+
`);
|
|
1090
|
+
}
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
active = false;
|
|
1094
|
+
stopTimer();
|
|
1095
|
+
const text = finalLabel ?? label;
|
|
1096
|
+
stream.write(animate ? `${CLEAR_LINE}${symbol} ${counter()}${text}
|
|
1097
|
+
` : `${symbol} ${counter()}${text}
|
|
1098
|
+
`);
|
|
1099
|
+
};
|
|
1100
|
+
return {
|
|
1101
|
+
start(next) {
|
|
1102
|
+
step += 1;
|
|
1103
|
+
label = next;
|
|
1104
|
+
active = true;
|
|
1105
|
+
if (animate) {
|
|
1106
|
+
frame = 0;
|
|
1107
|
+
render();
|
|
1108
|
+
stopTimer();
|
|
1109
|
+
timer = setInterval(() => {
|
|
1110
|
+
frame += 1;
|
|
1111
|
+
render();
|
|
1112
|
+
}, SPINNER_INTERVAL_MS);
|
|
1113
|
+
timer.unref?.();
|
|
1114
|
+
} else {
|
|
1115
|
+
stream.write(`${counter()}${label}
|
|
1116
|
+
`);
|
|
1117
|
+
}
|
|
1118
|
+
},
|
|
1119
|
+
update(next) {
|
|
1120
|
+
label = next;
|
|
1121
|
+
if (!active) {
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
if (animate) {
|
|
1125
|
+
render();
|
|
1126
|
+
} else {
|
|
1127
|
+
stream.write(`${counter()}${label}
|
|
1128
|
+
`);
|
|
1129
|
+
}
|
|
1130
|
+
},
|
|
1131
|
+
done(finalLabel) {
|
|
1132
|
+
finish(colors.green("\u2713"), finalLabel);
|
|
1133
|
+
},
|
|
1134
|
+
fail(finalLabel) {
|
|
1135
|
+
finish(colors.red("\u2717"), finalLabel);
|
|
1136
|
+
},
|
|
1137
|
+
clear() {
|
|
1138
|
+
stopTimer();
|
|
1139
|
+
if (active && animate) {
|
|
1140
|
+
stream.write(CLEAR_LINE);
|
|
1141
|
+
}
|
|
1142
|
+
active = false;
|
|
1143
|
+
}
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1010
1146
|
|
|
1011
1147
|
// src/cli/exit-codes.ts
|
|
1012
1148
|
var ExitCode = {
|
|
@@ -1033,7 +1169,7 @@ function messageForError(err) {
|
|
|
1033
1169
|
|
|
1034
1170
|
// src/cli/interactive.ts
|
|
1035
1171
|
import { isCancel, multiselect as clackMultiselect, select as clackSelect, text as clackText } from "@clack/prompts";
|
|
1036
|
-
var LAUNCHPAD_TAGLINE = "commit-whisper \xB7 \u{1F575}\uFE0F
|
|
1172
|
+
var LAUNCHPAD_TAGLINE = "commit-whisper \xB7 \u{1F575}\uFE0F I know what you did last commit";
|
|
1037
1173
|
var FLAGS_CHEATSHEET = [
|
|
1038
1174
|
"Common commands:",
|
|
1039
1175
|
" commit-whisper . analyze the current repository",
|
|
@@ -1072,11 +1208,16 @@ var PROVIDER_OPTIONS = [
|
|
|
1072
1208
|
{ value: "openai-compatible", label: "OpenAI-compatible" }
|
|
1073
1209
|
];
|
|
1074
1210
|
var BASE_URL_PROVIDERS = /* @__PURE__ */ new Set(["ollama", "openai-compatible"]);
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1211
|
+
function settingsSavedNote(provider) {
|
|
1212
|
+
const keyVar = aiKeyEnvVar(provider);
|
|
1213
|
+
if (keyVar === void 0) {
|
|
1214
|
+
return [
|
|
1215
|
+
"Ollama runs locally \u2014 no key needed, but it must be running:",
|
|
1216
|
+
" `ollama serve`, then `ollama pull <model>`. Saving selects it; it doesn't start it."
|
|
1217
|
+
].join("\n");
|
|
1218
|
+
}
|
|
1219
|
+
return `This provider reads its key from your environment (${keyVar}) \u2014 never entered here.`;
|
|
1220
|
+
}
|
|
1080
1221
|
function aiSegment(state) {
|
|
1081
1222
|
if (state.provider === void 0) {
|
|
1082
1223
|
return "\u26A0 not configured";
|
|
@@ -1100,8 +1241,8 @@ function buildLaunchpadOptions(state) {
|
|
|
1100
1241
|
{ value: "analyze-cwd", label: "Analyze this repository", hint: "the current directory" },
|
|
1101
1242
|
{ value: "analyze-remote", label: "Analyze a remote repository", hint: "clone a URL" },
|
|
1102
1243
|
{ value: "settings", label: "Settings", hint: "provider, model, default format" },
|
|
1103
|
-
{ value: "status", label: "
|
|
1104
|
-
{ value: "help", label: "Help
|
|
1244
|
+
{ value: "status", label: "Doctor", hint: "diagnose your setup" },
|
|
1245
|
+
{ value: "help", label: "Help", hint: "show the flag reference" }
|
|
1105
1246
|
];
|
|
1106
1247
|
if (state.licensed) {
|
|
1107
1248
|
options.push({ value: "deactivate", label: "Deactivate license", hint: "free this device" });
|
|
@@ -1120,19 +1261,16 @@ var STATUS_LABEL_WIDTH = 12;
|
|
|
1120
1261
|
function statusLabel(text) {
|
|
1121
1262
|
return text.padEnd(STATUS_LABEL_WIDTH);
|
|
1122
1263
|
}
|
|
1123
|
-
function
|
|
1264
|
+
function reachabilityAnnotation(reachability) {
|
|
1124
1265
|
switch (reachability.kind) {
|
|
1125
1266
|
case "reachable":
|
|
1126
|
-
return
|
|
1267
|
+
return "\u2713 reachable";
|
|
1127
1268
|
case "unreachable":
|
|
1128
|
-
return
|
|
1269
|
+
return `\u26A0 unreachable \u2014 ${reachability.reason}`;
|
|
1129
1270
|
default:
|
|
1130
|
-
return
|
|
1271
|
+
return "\u26A0 not configured";
|
|
1131
1272
|
}
|
|
1132
1273
|
}
|
|
1133
|
-
function aiBlock(state, reachability) {
|
|
1134
|
-
return [`${statusLabel("AI")}${aiSegment(state)}`, reachabilityLine(reachability)];
|
|
1135
|
-
}
|
|
1136
1274
|
function environmentBlock(envVars) {
|
|
1137
1275
|
const prefixes = envVars.map((v) => ` ${v.set ? "\u2713" : "\u2717"} ${v.name}`);
|
|
1138
1276
|
const stateColumn = Math.max(0, ...prefixes.map((p) => p.length)) + 2;
|
|
@@ -1146,15 +1284,91 @@ function environmentBlock(envVars) {
|
|
|
1146
1284
|
function repositoryLine(state) {
|
|
1147
1285
|
return state.isRepo ? `${statusLabel("Repository")}\u2713 ${cwdSegment(state)}` : `${statusLabel("Repository")}\u2014 not a git repo`;
|
|
1148
1286
|
}
|
|
1149
|
-
|
|
1150
|
-
|
|
1287
|
+
var CONFIG_LABEL_WIDTH = 14;
|
|
1288
|
+
function renderRows(rows) {
|
|
1289
|
+
const envColumn = Math.max(0, ...rows.map((r2) => (r2.envVar ?? "").length)) + 2;
|
|
1290
|
+
return rows.map((r2) => ` ${(r2.envVar ?? "").padEnd(envColumn)}${r2.label.padEnd(CONFIG_LABEL_WIDTH)}${r2.value}`);
|
|
1291
|
+
}
|
|
1292
|
+
function branchValue(branch) {
|
|
1293
|
+
if (branch === void 0) {
|
|
1294
|
+
return "HEAD (default)";
|
|
1295
|
+
}
|
|
1296
|
+
switch (branch.kind) {
|
|
1297
|
+
case "all":
|
|
1298
|
+
return "all branches";
|
|
1299
|
+
case "head":
|
|
1300
|
+
return "HEAD";
|
|
1301
|
+
default:
|
|
1302
|
+
return branch.name;
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
function formatValue(formats) {
|
|
1306
|
+
return formats !== void 0 && formats.length > 0 ? formats.join(", ") : "terminal (default)";
|
|
1307
|
+
}
|
|
1308
|
+
function settingsBlock(config) {
|
|
1309
|
+
if (config === void 0) {
|
|
1310
|
+
return [];
|
|
1311
|
+
}
|
|
1312
|
+
const baseUrlRow = config.llmBaseUrl === void 0 ? [] : [{ label: "Base URL", value: config.llmBaseUrl, envVar: "COMMIT_WHISPER_LLM_BASE_URL" }];
|
|
1313
|
+
const rows = [
|
|
1314
|
+
{ label: "Timezone", value: config.timezone ?? "UTC (default)", envVar: "COMMIT_WHISPER_TZ" },
|
|
1315
|
+
{ label: "Format", value: formatValue(config.outputFormats), envVar: "COMMIT_WHISPER_FORMAT" },
|
|
1316
|
+
{
|
|
1317
|
+
label: "Max commits",
|
|
1318
|
+
value: config.maxCommits === void 0 ? "unbounded" : String(config.maxCommits),
|
|
1319
|
+
envVar: "COMMIT_WHISPER_MAX_COMMITS"
|
|
1320
|
+
},
|
|
1321
|
+
...baseUrlRow
|
|
1322
|
+
];
|
|
1323
|
+
return ["", "Settings (saved in ~/.commit-whisper)", ...renderRows(rows)];
|
|
1324
|
+
}
|
|
1325
|
+
function runScopeBlock(config) {
|
|
1326
|
+
if (config === void 0) {
|
|
1327
|
+
return [];
|
|
1328
|
+
}
|
|
1329
|
+
const rows = [
|
|
1330
|
+
{ label: "Branch", value: branchValue(config.branch), envVar: "COMMIT_WHISPER_BRANCH" },
|
|
1331
|
+
{ label: "Author", value: config.authorFilter ?? "any (default)", envVar: "COMMIT_WHISPER_AUTHOR" },
|
|
1332
|
+
{ label: "Since", value: config.startDate ?? "\u2014 (unbounded)", envVar: "COMMIT_WHISPER_START_DATE" },
|
|
1333
|
+
{ label: "Until", value: config.endDate ?? "\u2014 (unbounded)", envVar: "COMMIT_WHISPER_END_DATE" },
|
|
1334
|
+
{ label: "No-merges", value: config.noMerges === true ? "on" : "off (default)", envVar: "COMMIT_WHISPER_NO_MERGES" },
|
|
1335
|
+
{ label: "Output path", value: config.outputPath ?? "\u2014 (auto)", envVar: "COMMIT_WHISPER_OUT" },
|
|
1336
|
+
{ label: "AI mode", value: config.aiMode ?? "auto (default)", envVar: "COMMIT_WHISPER_AI_MODE" }
|
|
1337
|
+
];
|
|
1338
|
+
return ["", "Run scope (env vars / flags only \u2014 not saved)", ...renderRows(rows)];
|
|
1339
|
+
}
|
|
1340
|
+
function colorState(color) {
|
|
1341
|
+
if (color === void 0) {
|
|
1342
|
+
return "auto";
|
|
1343
|
+
}
|
|
1344
|
+
return color ? "on" : "off";
|
|
1345
|
+
}
|
|
1346
|
+
function operationalBlock(config) {
|
|
1347
|
+
if (config === void 0 || config.logLevel === void 0 && config.color === void 0) {
|
|
1348
|
+
return [];
|
|
1349
|
+
}
|
|
1350
|
+
const rows = [
|
|
1351
|
+
{ label: "Log level", value: config.logLevel ?? "normal (default)", envVar: "COMMIT_WHISPER_LOG_LEVEL" },
|
|
1352
|
+
{ label: "Color", value: colorState(config.color), envVar: "NO_COLOR / FORCE_COLOR" }
|
|
1353
|
+
];
|
|
1354
|
+
return ["", "Operational", ...renderRows(rows)];
|
|
1355
|
+
}
|
|
1356
|
+
function formatStatusReport(state, envVars, reachability, config) {
|
|
1357
|
+
const licenseHead = `${statusLabel("License")}${TIER_LABEL[state.tier]}`;
|
|
1358
|
+
const aiHead = `${statusLabel("AI")}${aiSegment(state)}`;
|
|
1359
|
+
const annotationColumn = Math.max(licenseHead.length, aiHead.length) + 3;
|
|
1360
|
+
const licenseLine = state.tier === "free" ? `${licenseHead.padEnd(annotationColumn)}100-commit cap` : licenseHead;
|
|
1361
|
+
const aiLine = `${aiHead.padEnd(annotationColumn)}${reachabilityAnnotation(reachability)}`;
|
|
1151
1362
|
const lines = [
|
|
1152
|
-
"
|
|
1363
|
+
"Doctor",
|
|
1153
1364
|
"",
|
|
1154
|
-
|
|
1155
|
-
|
|
1365
|
+
licenseLine,
|
|
1366
|
+
aiLine,
|
|
1367
|
+
repositoryLine(state),
|
|
1156
1368
|
...environmentBlock(envVars),
|
|
1157
|
-
|
|
1369
|
+
...settingsBlock(config),
|
|
1370
|
+
...runScopeBlock(config),
|
|
1371
|
+
...operationalBlock(config)
|
|
1158
1372
|
];
|
|
1159
1373
|
if (reachability.kind === "not-configured") {
|
|
1160
1374
|
lines.push("", NO_AI_FIX);
|
|
@@ -1234,6 +1448,28 @@ function writeLine(output, text) {
|
|
|
1234
1448
|
output.write(text.endsWith("\n") ? text : `${text}
|
|
1235
1449
|
`);
|
|
1236
1450
|
}
|
|
1451
|
+
function isInteractive(output) {
|
|
1452
|
+
return output.isTTY === true;
|
|
1453
|
+
}
|
|
1454
|
+
function clearScreen(output) {
|
|
1455
|
+
output.write("\x1B[2J\x1B[3J\x1B[H");
|
|
1456
|
+
}
|
|
1457
|
+
async function waitForKey(output) {
|
|
1458
|
+
writeLine(output, "");
|
|
1459
|
+
output.write("Press any key to return to the menu\u2026 (Esc to quit)");
|
|
1460
|
+
const stdin = process.stdin;
|
|
1461
|
+
const wasRaw = stdin.isRaw === true;
|
|
1462
|
+
stdin.setRawMode?.(true);
|
|
1463
|
+
stdin.resume();
|
|
1464
|
+
return await new Promise((resolve) => {
|
|
1465
|
+
stdin.once("data", (data) => {
|
|
1466
|
+
stdin.setRawMode?.(wasRaw);
|
|
1467
|
+
stdin.pause();
|
|
1468
|
+
const key = data.toString("utf8");
|
|
1469
|
+
resolve(key === "" || key === "\x1B" ? "quit" : "continue");
|
|
1470
|
+
});
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1237
1473
|
function clackLaunchpadSelect(output) {
|
|
1238
1474
|
return async ({ message, options }) => {
|
|
1239
1475
|
const result = await clackSelect({ message, options, output });
|
|
@@ -1248,6 +1484,7 @@ function clackGuidedPrompts(output) {
|
|
|
1248
1484
|
message: opts.message,
|
|
1249
1485
|
placeholder: opts.placeholder,
|
|
1250
1486
|
defaultValue: opts.defaultValue,
|
|
1487
|
+
initialValue: opts.initialValue,
|
|
1251
1488
|
// `@clack` may pass `undefined` (empty input); our validators are total over strings.
|
|
1252
1489
|
validate: validate === void 0 ? void 0 : (value) => validate(value ?? ""),
|
|
1253
1490
|
output
|
|
@@ -1281,7 +1518,7 @@ function validateRemoteUrl(value) {
|
|
|
1281
1518
|
function errorOf(result) {
|
|
1282
1519
|
return "error" in result ? result.error : void 0;
|
|
1283
1520
|
}
|
|
1284
|
-
async function collectGuidedInputs(prompts) {
|
|
1521
|
+
async function collectGuidedInputs(prompts, initialFormats = ["terminal"]) {
|
|
1285
1522
|
const limitRaw = await prompts.text({
|
|
1286
1523
|
message: "Limit \u2014 most-recent commits to analyze",
|
|
1287
1524
|
placeholder: "all history",
|
|
@@ -1301,7 +1538,7 @@ async function collectGuidedInputs(prompts) {
|
|
|
1301
1538
|
const formats = await prompts.multiselect({
|
|
1302
1539
|
message: "Output \u2014 one or more formats",
|
|
1303
1540
|
options: OUTPUT_FORMAT_OPTIONS,
|
|
1304
|
-
initialValues:
|
|
1541
|
+
initialValues: initialFormats
|
|
1305
1542
|
});
|
|
1306
1543
|
if (formats === null) {
|
|
1307
1544
|
return null;
|
|
@@ -1321,6 +1558,17 @@ async function collectGuidedInputs(prompts) {
|
|
|
1321
1558
|
flags.outputFormats = formats.length > 0 ? formats : ["terminal"];
|
|
1322
1559
|
return flags;
|
|
1323
1560
|
}
|
|
1561
|
+
async function loadDefaultFormats(deps) {
|
|
1562
|
+
if (deps.loadSettings === void 0) {
|
|
1563
|
+
return ["terminal"];
|
|
1564
|
+
}
|
|
1565
|
+
try {
|
|
1566
|
+
const saved = (await deps.loadSettings()).outputFormats;
|
|
1567
|
+
return saved !== void 0 && saved.length > 0 ? saved : ["terminal"];
|
|
1568
|
+
} catch {
|
|
1569
|
+
return ["terminal"];
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1324
1572
|
async function runGuidedAnalyze(deps, mode, output) {
|
|
1325
1573
|
if (deps.state.provider === void 0) {
|
|
1326
1574
|
writeLine(output, NO_AI_INTERSTITIAL);
|
|
@@ -1341,7 +1589,7 @@ async function runGuidedAnalyze(deps, mode, output) {
|
|
|
1341
1589
|
);
|
|
1342
1590
|
}
|
|
1343
1591
|
}
|
|
1344
|
-
const inputs = await collectGuidedInputs(prompts);
|
|
1592
|
+
const inputs = await collectGuidedInputs(prompts, await loadDefaultFormats(deps));
|
|
1345
1593
|
if (inputs === null) {
|
|
1346
1594
|
return;
|
|
1347
1595
|
}
|
|
@@ -1352,15 +1600,25 @@ async function runGuidedAnalyze(deps, mode, output) {
|
|
|
1352
1600
|
writeLine(output, `\u25B8 Next time: ${formatEquivalentCommand(target, flags)}`);
|
|
1353
1601
|
}
|
|
1354
1602
|
async function runStatusDoctor(deps, output) {
|
|
1603
|
+
let envDiagnostics = deps.envDiagnostics ?? [];
|
|
1604
|
+
let doctorConfig = deps.doctorConfig;
|
|
1605
|
+
if (deps.refreshDoctor !== void 0) {
|
|
1606
|
+
const fresh = await deps.refreshDoctor();
|
|
1607
|
+
deps.state.provider = fresh.provider;
|
|
1608
|
+
deps.state.llmModel = fresh.llmModel;
|
|
1609
|
+
envDiagnostics = fresh.envDiagnostics;
|
|
1610
|
+
doctorConfig = fresh.doctorConfig;
|
|
1611
|
+
}
|
|
1355
1612
|
let reachability = { kind: "not-configured" };
|
|
1356
1613
|
if (deps.state.provider !== void 0 && deps.probeReachability !== void 0) {
|
|
1614
|
+
writeLine(output, `Testing connection to ${deps.state.provider}\u2026`);
|
|
1357
1615
|
try {
|
|
1358
1616
|
reachability = await deps.probeReachability();
|
|
1359
1617
|
} catch (err) {
|
|
1360
1618
|
reachability = { kind: "unreachable", reason: err instanceof Error ? err.message : "probe failed" };
|
|
1361
1619
|
}
|
|
1362
1620
|
}
|
|
1363
|
-
writeLine(output, formatStatusReport(deps.state,
|
|
1621
|
+
writeLine(output, formatStatusReport(deps.state, envDiagnostics, reachability, doctorConfig));
|
|
1364
1622
|
}
|
|
1365
1623
|
async function runSettings(deps, output) {
|
|
1366
1624
|
const prompts = deps.prompts ?? clackGuidedPrompts(output);
|
|
@@ -1380,7 +1638,15 @@ async function runSettings(deps, output) {
|
|
|
1380
1638
|
if (provider === null) {
|
|
1381
1639
|
return;
|
|
1382
1640
|
}
|
|
1383
|
-
const model = await prompts.text({
|
|
1641
|
+
const model = await prompts.text({
|
|
1642
|
+
message: "Model",
|
|
1643
|
+
placeholder: "e.g. llama3 / gpt-4o",
|
|
1644
|
+
initialValue: current.llmModel,
|
|
1645
|
+
// A model is REQUIRED: every run narrates with it, and there is no default —
|
|
1646
|
+
// saving a provider without one persists a config that fails at run time
|
|
1647
|
+
// ("llmModel is missing"). Require it here so Settings can't save a dead config.
|
|
1648
|
+
validate: (v) => v.trim() === "" ? "A model is required \u2014 every run narrates with it (e.g. gpt-4o, llama3)." : void 0
|
|
1649
|
+
});
|
|
1384
1650
|
if (model === null) {
|
|
1385
1651
|
return;
|
|
1386
1652
|
}
|
|
@@ -1388,46 +1654,56 @@ async function runSettings(deps, output) {
|
|
|
1388
1654
|
if (BASE_URL_PROVIDERS.has(provider)) {
|
|
1389
1655
|
baseUrl = await prompts.text({
|
|
1390
1656
|
message: "Base URL",
|
|
1391
|
-
placeholder: "e.g. http://localhost:11434"
|
|
1657
|
+
placeholder: "e.g. http://localhost:11434",
|
|
1658
|
+
initialValue: current.llmBaseUrl
|
|
1392
1659
|
});
|
|
1393
1660
|
if (baseUrl === null) {
|
|
1394
1661
|
return;
|
|
1395
1662
|
}
|
|
1396
1663
|
}
|
|
1397
|
-
const
|
|
1398
|
-
message: "Default output
|
|
1399
|
-
options: OUTPUT_FORMAT_OPTIONS
|
|
1400
|
-
|
|
1664
|
+
const formats = await prompts.multiselect({
|
|
1665
|
+
message: "Default output \u2014 one or more formats",
|
|
1666
|
+
options: OUTPUT_FORMAT_OPTIONS,
|
|
1667
|
+
initialValues: current.outputFormats
|
|
1401
1668
|
});
|
|
1402
|
-
if (
|
|
1403
|
-
return;
|
|
1404
|
-
}
|
|
1405
|
-
const timezone = await prompts.text({ message: "Timezone (optional)", placeholder: "e.g. UTC / Europe/Athens" });
|
|
1406
|
-
if (timezone === null) {
|
|
1669
|
+
if (formats === null) {
|
|
1407
1670
|
return;
|
|
1408
1671
|
}
|
|
1409
|
-
const
|
|
1410
|
-
message: "
|
|
1411
|
-
placeholder: "
|
|
1412
|
-
|
|
1672
|
+
const timezone = await prompts.text({
|
|
1673
|
+
message: "Timezone (optional)",
|
|
1674
|
+
placeholder: "e.g. UTC / Europe/Athens",
|
|
1675
|
+
initialValue: current.timezone
|
|
1413
1676
|
});
|
|
1414
|
-
if (
|
|
1677
|
+
if (timezone === null) {
|
|
1415
1678
|
return;
|
|
1416
1679
|
}
|
|
1417
|
-
const data = assembleSettings({ provider, model, baseUrl,
|
|
1680
|
+
const data = assembleSettings({ provider, model, baseUrl, formats, timezone });
|
|
1418
1681
|
if (deps.saveSettings === void 0) {
|
|
1419
1682
|
return;
|
|
1420
1683
|
}
|
|
1421
1684
|
try {
|
|
1422
1685
|
const path = await deps.saveSettings(data);
|
|
1423
1686
|
writeLine(output, `\u2713 Saved to ${path}`);
|
|
1424
|
-
writeLine(output,
|
|
1687
|
+
writeLine(output, settingsSavedNote(provider));
|
|
1688
|
+
await refreshAiState(deps);
|
|
1425
1689
|
} catch (err) {
|
|
1426
1690
|
writeLine(output, `\u26A0 Could not save settings: ${err instanceof Error ? err.message : "write failed"}`);
|
|
1427
1691
|
}
|
|
1428
1692
|
}
|
|
1693
|
+
async function refreshAiState(deps) {
|
|
1694
|
+
if (deps.reloadAiState === void 0) {
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
try {
|
|
1698
|
+
const ai = await deps.reloadAiState();
|
|
1699
|
+
deps.state.provider = ai.provider;
|
|
1700
|
+
deps.state.llmModel = ai.llmModel;
|
|
1701
|
+
} catch {
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1429
1704
|
function assembleSettings(input) {
|
|
1430
|
-
const
|
|
1705
|
+
const outputFormats = input.formats.length > 0 ? input.formats : ["terminal"];
|
|
1706
|
+
const data = { provider: input.provider, outputFormats };
|
|
1431
1707
|
const model = input.model.trim();
|
|
1432
1708
|
if (model !== "") {
|
|
1433
1709
|
data.llmModel = model;
|
|
@@ -1440,10 +1716,6 @@ function assembleSettings(input) {
|
|
|
1440
1716
|
if (timezone !== "") {
|
|
1441
1717
|
data.timezone = timezone;
|
|
1442
1718
|
}
|
|
1443
|
-
const limit = interpretLimit(input.limitRaw);
|
|
1444
|
-
if ("maxCommits" in limit && limit.maxCommits !== void 0) {
|
|
1445
|
-
data.maxCommits = limit.maxCommits;
|
|
1446
|
-
}
|
|
1447
1719
|
return data;
|
|
1448
1720
|
}
|
|
1449
1721
|
async function runActivate(deps, output) {
|
|
@@ -1458,7 +1730,9 @@ async function runActivate(deps, output) {
|
|
|
1458
1730
|
try {
|
|
1459
1731
|
const outcome = await deps.activateLicense(key);
|
|
1460
1732
|
if (outcome.ok) {
|
|
1461
|
-
|
|
1733
|
+
deps.state.licensed = true;
|
|
1734
|
+
deps.state.tier = outcome.tier;
|
|
1735
|
+
writeLine(output, `\u2713 License activated \u2014 ${TIER_LABEL[outcome.tier]} tier.`);
|
|
1462
1736
|
} else {
|
|
1463
1737
|
writeLine(output, `\u26A0 ${outcome.reason}`);
|
|
1464
1738
|
}
|
|
@@ -1485,6 +1759,8 @@ async function runDeactivate(deps, output) {
|
|
|
1485
1759
|
try {
|
|
1486
1760
|
const outcome = await deps.deactivateLicense();
|
|
1487
1761
|
if (outcome.ok) {
|
|
1762
|
+
deps.state.licensed = false;
|
|
1763
|
+
deps.state.tier = "free";
|
|
1488
1764
|
writeLine(output, "\u2713 License deactivated \u2014 freed on this device. Re-activate anytime with your key.");
|
|
1489
1765
|
} else {
|
|
1490
1766
|
writeLine(output, `\u26A0 ${outcome.reason}`);
|
|
@@ -1556,14 +1832,30 @@ function assertNeverAction(action) {
|
|
|
1556
1832
|
async function runLaunchpad(deps) {
|
|
1557
1833
|
const output = deps.output ?? process.stderr;
|
|
1558
1834
|
const select = deps.select ?? clackLaunchpadSelect(output);
|
|
1559
|
-
const
|
|
1560
|
-
|
|
1561
|
-
|
|
1835
|
+
const repaint = deps.repaint ?? isInteractive(output);
|
|
1836
|
+
const pause = deps.waitForKey ?? waitForKey;
|
|
1837
|
+
const writeHeader = () => {
|
|
1838
|
+
writeLine(output, LAUNCHPAD_TAGLINE);
|
|
1839
|
+
writeLine(output, formatReadinessLine(deps.state));
|
|
1840
|
+
};
|
|
1841
|
+
if (!repaint) {
|
|
1842
|
+
writeHeader();
|
|
1843
|
+
}
|
|
1562
1844
|
for (; ; ) {
|
|
1845
|
+
if (repaint) {
|
|
1846
|
+
clearScreen(output);
|
|
1847
|
+
writeHeader();
|
|
1848
|
+
}
|
|
1849
|
+
const options = buildLaunchpadOptions(deps.state);
|
|
1563
1850
|
const action = await select({ message: "What would you like to do?", options }) ?? "quit";
|
|
1564
1851
|
if (await dispatchAction(deps, action, output) === "quit") {
|
|
1565
1852
|
return ExitCode.Success;
|
|
1566
1853
|
}
|
|
1854
|
+
if (repaint && await pause(output) === "quit") {
|
|
1855
|
+
writeLine(output, "");
|
|
1856
|
+
writeLine(output, FLAGS_CHEATSHEET);
|
|
1857
|
+
return ExitCode.Success;
|
|
1858
|
+
}
|
|
1567
1859
|
}
|
|
1568
1860
|
}
|
|
1569
1861
|
|
|
@@ -2098,7 +2390,7 @@ var ownershipByArea = (model) => {
|
|
|
2098
2390
|
topFiles: topAreas(fileAreas, HOTSPOT_TOP_FILES)
|
|
2099
2391
|
});
|
|
2100
2392
|
};
|
|
2101
|
-
var CO_AUTHOR_TRAILER = /^[ \t]*co-authored-by:[ \t]*(
|
|
2393
|
+
var CO_AUTHOR_TRAILER = /^[ \t]*co-authored-by:[ \t]*(.+)$/gim;
|
|
2102
2394
|
function coAuthorKey(trailer) {
|
|
2103
2395
|
const angle = /<([^<>]+)>/.exec(trailer);
|
|
2104
2396
|
return (angle ? angle[1] : trailer).trim().toLowerCase();
|
|
@@ -3154,6 +3446,8 @@ var FullNarrativeSchema = NarrativeSchema.extend({
|
|
|
3154
3446
|
|
|
3155
3447
|
// src/assemble/report-schema.ts
|
|
3156
3448
|
var SCHEMA_VERSION = "1.0.0";
|
|
3449
|
+
var ProviderSchema = z2.enum(["ollama", "openai", "gemini", "anthropic", "openai-compatible"]);
|
|
3450
|
+
var TierSchema = z2.enum(["free", "single-device", "unlimited"]);
|
|
3157
3451
|
var JsonValueSchema = z2.lazy(
|
|
3158
3452
|
() => z2.union([
|
|
3159
3453
|
z2.string(),
|
|
@@ -3186,11 +3480,42 @@ var NarrativeSchema2 = z2.object({
|
|
|
3186
3480
|
message: "escalation must be present exactly when the confidence level is 'low'"
|
|
3187
3481
|
}).optional()
|
|
3188
3482
|
}).strict();
|
|
3483
|
+
var ProvenanceSchema = z2.object({
|
|
3484
|
+
repo: z2.object({
|
|
3485
|
+
name: z2.string(),
|
|
3486
|
+
target: z2.string(),
|
|
3487
|
+
// credential-stripped — never a token-bearing URL
|
|
3488
|
+
source: z2.enum(["local", "remote"]),
|
|
3489
|
+
branch: z2.string().optional()
|
|
3490
|
+
}).strict().optional(),
|
|
3491
|
+
scale: z2.object({
|
|
3492
|
+
totalCommits: z2.number().optional(),
|
|
3493
|
+
analyzedCommits: z2.number().optional(),
|
|
3494
|
+
contributors: z2.number().optional()
|
|
3495
|
+
}).strict().optional(),
|
|
3496
|
+
// Present ONLY when narration ran (absent on `--no-ai` / fail-open degraded),
|
|
3497
|
+
// mirroring the `narrative`-subtree presence rule exactly.
|
|
3498
|
+
ai: z2.object({
|
|
3499
|
+
provider: ProviderSchema,
|
|
3500
|
+
model: z2.string()
|
|
3501
|
+
}).strict().optional(),
|
|
3502
|
+
run: z2.object({
|
|
3503
|
+
generatedAt: z2.string(),
|
|
3504
|
+
// == RunConfig.analysisTimestamp, never Date.now()
|
|
3505
|
+
toolVersion: z2.string()
|
|
3506
|
+
}).strict().optional(),
|
|
3507
|
+
entitlement: z2.object({
|
|
3508
|
+
tier: TierSchema,
|
|
3509
|
+
commitCap: z2.number().optional()
|
|
3510
|
+
// present only on the Free tier
|
|
3511
|
+
}).strict().optional()
|
|
3512
|
+
}).strict();
|
|
3189
3513
|
var ReportSchema = z2.object({
|
|
3190
3514
|
schemaVersion: z2.literal(SCHEMA_VERSION),
|
|
3191
3515
|
degraded: z2.boolean(),
|
|
3192
3516
|
analysis: AnalysisSchema,
|
|
3193
|
-
narrative: NarrativeSchema2.optional()
|
|
3517
|
+
narrative: NarrativeSchema2.optional(),
|
|
3518
|
+
provenance: ProvenanceSchema.optional()
|
|
3194
3519
|
}).strict();
|
|
3195
3520
|
|
|
3196
3521
|
// src/assemble/report.ts
|
|
@@ -3203,22 +3528,33 @@ function assembleReport(input) {
|
|
|
3203
3528
|
if (input.narrative !== void 0) {
|
|
3204
3529
|
report.narrative = structuredClone(input.narrative);
|
|
3205
3530
|
}
|
|
3531
|
+
if (input.provenance !== void 0) {
|
|
3532
|
+
report.provenance = structuredClone(input.provenance);
|
|
3533
|
+
}
|
|
3206
3534
|
return report;
|
|
3207
3535
|
}
|
|
3208
|
-
function reportFromOutcome(analysis, outcome) {
|
|
3536
|
+
function reportFromOutcome(analysis, outcome, provenance) {
|
|
3209
3537
|
switch (outcome.kind) {
|
|
3210
3538
|
case "narrated":
|
|
3211
|
-
return assembleReport({ analysis, narrative: outcome.narrative, degraded: false });
|
|
3539
|
+
return assembleReport({ analysis, narrative: outcome.narrative, degraded: false, provenance });
|
|
3212
3540
|
case "skipped":
|
|
3213
|
-
return assembleReport({ analysis, degraded: false });
|
|
3541
|
+
return assembleReport({ analysis, degraded: false, provenance: withoutAi(provenance) });
|
|
3214
3542
|
// intentional metrics-only
|
|
3215
3543
|
case "degraded":
|
|
3216
|
-
return assembleReport({ analysis, degraded: true });
|
|
3544
|
+
return assembleReport({ analysis, degraded: true, provenance: withoutAi(provenance) });
|
|
3217
3545
|
// fail-open, narrative lost
|
|
3218
3546
|
default:
|
|
3219
3547
|
return assertNever(outcome);
|
|
3220
3548
|
}
|
|
3221
3549
|
}
|
|
3550
|
+
function withoutAi(provenance) {
|
|
3551
|
+
if (provenance?.ai === void 0) {
|
|
3552
|
+
return provenance;
|
|
3553
|
+
}
|
|
3554
|
+
const rest = { ...provenance };
|
|
3555
|
+
delete rest.ai;
|
|
3556
|
+
return rest;
|
|
3557
|
+
}
|
|
3222
3558
|
function assertNever(value) {
|
|
3223
3559
|
throw new Error(`Unhandled narrate outcome: ${JSON.stringify(value)}`);
|
|
3224
3560
|
}
|
|
@@ -3529,7 +3865,11 @@ function resolveModel(config) {
|
|
|
3529
3865
|
return createOpenAICompatible({ name: "openai-compatible", baseURL, apiKey: config.aiKey?.reveal() })(model);
|
|
3530
3866
|
}
|
|
3531
3867
|
case "ollama": {
|
|
3532
|
-
|
|
3868
|
+
let base = cleanBaseUrl2(config.llmBaseUrl) ?? OLLAMA_DEFAULT_BASE_URL2;
|
|
3869
|
+
while (base.endsWith("/v1")) {
|
|
3870
|
+
base = base.slice(0, -3);
|
|
3871
|
+
}
|
|
3872
|
+
const baseURL = `${base}/v1`;
|
|
3533
3873
|
return createOpenAICompatible({ name: "ollama", baseURL })(model);
|
|
3534
3874
|
}
|
|
3535
3875
|
case void 0:
|
|
@@ -3565,7 +3905,7 @@ function cleanBaseUrl2(baseUrl) {
|
|
|
3565
3905
|
if (baseUrl === void 0) {
|
|
3566
3906
|
return void 0;
|
|
3567
3907
|
}
|
|
3568
|
-
const trimmed = baseUrl.trim()
|
|
3908
|
+
const trimmed = stripTrailingSlashes(baseUrl.trim());
|
|
3569
3909
|
return trimmed === "" ? void 0 : trimmed;
|
|
3570
3910
|
}
|
|
3571
3911
|
function assertNeverProvider(provider) {
|
|
@@ -3629,18 +3969,87 @@ function classifyReport(report) {
|
|
|
3629
3969
|
};
|
|
3630
3970
|
}
|
|
3631
3971
|
|
|
3972
|
+
// src/render/html/health.ts
|
|
3973
|
+
var HEALTH_GLYPH = {
|
|
3974
|
+
ok: "\u25CF",
|
|
3975
|
+
watch: "\u25D0",
|
|
3976
|
+
risk: "\u25B2",
|
|
3977
|
+
na: "\u25CB"
|
|
3978
|
+
};
|
|
3979
|
+
var HEALTH_LABEL = {
|
|
3980
|
+
ok: "ok",
|
|
3981
|
+
watch: "watch",
|
|
3982
|
+
risk: "risk",
|
|
3983
|
+
na: "n/a"
|
|
3984
|
+
};
|
|
3985
|
+
function field(value, key) {
|
|
3986
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
3987
|
+
return void 0;
|
|
3988
|
+
}
|
|
3989
|
+
const v = value[key];
|
|
3990
|
+
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
3991
|
+
}
|
|
3992
|
+
function higherBetter(key, okMin, watchMin) {
|
|
3993
|
+
return (value) => {
|
|
3994
|
+
const n = field(value, key);
|
|
3995
|
+
if (n === void 0) return "ok";
|
|
3996
|
+
if (n >= okMin) return "ok";
|
|
3997
|
+
if (n >= watchMin) return "watch";
|
|
3998
|
+
return "risk";
|
|
3999
|
+
};
|
|
4000
|
+
}
|
|
4001
|
+
function lowerBetter(key, okMax, watchMax) {
|
|
4002
|
+
return (value) => {
|
|
4003
|
+
const n = field(value, key);
|
|
4004
|
+
if (n === void 0) return "ok";
|
|
4005
|
+
if (n <= okMax) return "ok";
|
|
4006
|
+
if (n <= watchMax) return "watch";
|
|
4007
|
+
return "risk";
|
|
4008
|
+
};
|
|
4009
|
+
}
|
|
4010
|
+
var REGISTRY = {
|
|
4011
|
+
// Knowledge concentration — fewer key people is riskier.
|
|
4012
|
+
"b-bus-factor": higherBetter("busFactor", 3, 2),
|
|
4013
|
+
"f-bus-factor-risk": higherBetter("busFactor", 3, 2),
|
|
4014
|
+
// Contribution concentration — a very high top share concentrates load.
|
|
4015
|
+
"b-contribution-distribution": lowerBetter("topCommitSharePct", 60, 80),
|
|
4016
|
+
// Message quality — higher Conventional-Commits adherence is healthier.
|
|
4017
|
+
"c-conventional-commits": higherBetter("adherenceSharePct", 70, 40),
|
|
4018
|
+
// Low-information commit messages — fewer is healthier.
|
|
4019
|
+
"c-low-information-rate": lowerBetter("lowInfoSharePct", 10, 25),
|
|
4020
|
+
// Workflow discipline — a high direct-to-default share is riskier.
|
|
4021
|
+
"d-direct-to-default": lowerBetter("directToDefaultSharePct", 20, 50),
|
|
4022
|
+
// Overall hygiene composite (0–100).
|
|
4023
|
+
"f-hygiene-score": higherBetter("score", 75, 50)
|
|
4024
|
+
};
|
|
4025
|
+
function classifyHealth(metric) {
|
|
4026
|
+
if (metric.status === "not_available") {
|
|
4027
|
+
return "na";
|
|
4028
|
+
}
|
|
4029
|
+
const classifier = REGISTRY[metric.id];
|
|
4030
|
+
return classifier === void 0 ? "ok" : classifier(metric.value);
|
|
4031
|
+
}
|
|
4032
|
+
|
|
3632
4033
|
// src/render/terminal/terminal-renderer.ts
|
|
4034
|
+
var GROUPS = [
|
|
4035
|
+
{ id: "A", title: "Activity & Cadence", description: "How the project moves over time." },
|
|
4036
|
+
{ id: "B", title: "Contribution & Ownership", description: "How the work is distributed across the team." },
|
|
4037
|
+
{ id: "C", title: "Commit Message Quality", description: "How clearly the history communicates intent." },
|
|
4038
|
+
{ id: "D", title: "Branching & Merge Structure", description: "How branching and merging are structured." },
|
|
4039
|
+
{ id: "E", title: "Churn & Hotspots", description: "Where change and instability concentrate." },
|
|
4040
|
+
{ id: "F", title: "Repository Health Signals", description: "Overall repository health signals." }
|
|
4041
|
+
];
|
|
3633
4042
|
var DEGRADED_BANNER = "\u26A0 Narrative unavailable \u2014 raw analysis below";
|
|
3634
4043
|
var METRICS_ONLY_NOTE = "Metrics-only run \u2014 no AI narrative requested";
|
|
3635
4044
|
function renderTerminal(report, opts = {}) {
|
|
3636
4045
|
const c = opts.color === void 0 ? pc2.createColors() : pc2.createColors(opts.color);
|
|
3637
4046
|
const route = classifyReport(report);
|
|
3638
|
-
return route.kind === "showpiece" ? renderShowpiece(route.report, c) : renderSubstrate(route.analysis, route.framing, c);
|
|
4047
|
+
return route.kind === "showpiece" ? renderShowpiece(route.report, report.provenance, c) : renderSubstrate(route.analysis, route.framing, report.provenance, c);
|
|
3639
4048
|
}
|
|
3640
|
-
function renderShowpiece(report, c) {
|
|
4049
|
+
function renderShowpiece(report, provenance, c) {
|
|
3641
4050
|
const { summary, explanation, coaching, confidence } = report.narrative;
|
|
3642
4051
|
return [
|
|
3643
|
-
|
|
4052
|
+
masthead(provenance, c),
|
|
3644
4053
|
...confidenceBand(confidence, c),
|
|
3645
4054
|
"",
|
|
3646
4055
|
c.bold("Summary"),
|
|
@@ -3666,15 +4075,77 @@ function renderShowpiece(report, c) {
|
|
|
3666
4075
|
]),
|
|
3667
4076
|
coaching.closingSummary,
|
|
3668
4077
|
"",
|
|
3669
|
-
|
|
4078
|
+
metricsSection(report.analysis, report.narrative.explanations, c)
|
|
3670
4079
|
].join("\n");
|
|
3671
4080
|
}
|
|
3672
|
-
function renderSubstrate(analysis, framing, c) {
|
|
4081
|
+
function renderSubstrate(analysis, framing, provenance, c) {
|
|
3673
4082
|
const banner = framing === "degraded" ? c.bold(c.yellow(DEGRADED_BANNER)) : c.dim(METRICS_ONLY_NOTE);
|
|
3674
|
-
return [
|
|
4083
|
+
return [masthead(provenance, c), "", banner, "", metricsSection(analysis, void 0, c)].join("\n");
|
|
4084
|
+
}
|
|
4085
|
+
function masthead(provenance, c) {
|
|
4086
|
+
const lines = [c.bold("commit-whisper")];
|
|
4087
|
+
const chips = provenanceChips(provenance);
|
|
4088
|
+
if (chips !== "") {
|
|
4089
|
+
lines.push(c.dim(chips));
|
|
4090
|
+
}
|
|
4091
|
+
const cap = capLine(provenance);
|
|
4092
|
+
if (cap !== "") {
|
|
4093
|
+
lines.push(c.dim(cap));
|
|
4094
|
+
}
|
|
4095
|
+
return lines.join("\n");
|
|
4096
|
+
}
|
|
4097
|
+
function provenanceChips(provenance) {
|
|
4098
|
+
const repo = provenance?.repo;
|
|
4099
|
+
const scale = provenance?.scale;
|
|
4100
|
+
const chips = [];
|
|
4101
|
+
if (repo?.name !== void 0) {
|
|
4102
|
+
chips.push(repo.name);
|
|
4103
|
+
}
|
|
4104
|
+
if (repo?.branch !== void 0) {
|
|
4105
|
+
chips.push(repo.branch);
|
|
4106
|
+
}
|
|
4107
|
+
const commits = scale?.totalCommits ?? scale?.analyzedCommits;
|
|
4108
|
+
if (commits !== void 0) {
|
|
4109
|
+
chips.push(`${formatCount(commits)} ${commits === 1 ? "commit" : "commits"}`);
|
|
4110
|
+
}
|
|
4111
|
+
if (scale?.contributors !== void 0) {
|
|
4112
|
+
chips.push(`${formatCount(scale.contributors)} ${scale.contributors === 1 ? "contributor" : "contributors"}`);
|
|
4113
|
+
}
|
|
4114
|
+
const generatedAt = provenance?.run?.generatedAt;
|
|
4115
|
+
if (generatedAt !== void 0) {
|
|
4116
|
+
chips.push(`analyzed ${isoDate(generatedAt)}`);
|
|
4117
|
+
}
|
|
4118
|
+
return chips.join(" \xB7 ");
|
|
3675
4119
|
}
|
|
3676
|
-
function
|
|
3677
|
-
|
|
4120
|
+
function capLine(provenance) {
|
|
4121
|
+
if (provenance?.entitlement?.tier !== "free") {
|
|
4122
|
+
return "";
|
|
4123
|
+
}
|
|
4124
|
+
const analyzed = provenance.scale?.analyzedCommits;
|
|
4125
|
+
if (analyzed === void 0) {
|
|
4126
|
+
return "";
|
|
4127
|
+
}
|
|
4128
|
+
const total = provenance.scale?.totalCommits;
|
|
4129
|
+
const detail = total === void 0 ? `${formatCount(analyzed)} commits analyzed` : `${formatCount(analyzed)} of ${formatCount(total)} commits analyzed`;
|
|
4130
|
+
return `Free \xB7 ${detail}`;
|
|
4131
|
+
}
|
|
4132
|
+
function formatCount(n) {
|
|
4133
|
+
if (!Number.isFinite(n)) {
|
|
4134
|
+
return "0";
|
|
4135
|
+
}
|
|
4136
|
+
const negative = n < 0;
|
|
4137
|
+
const digits = Math.abs(Math.trunc(n)).toString();
|
|
4138
|
+
let grouped = "";
|
|
4139
|
+
for (let i = 0; i < digits.length; i++) {
|
|
4140
|
+
if (i > 0 && (digits.length - i) % 3 === 0) {
|
|
4141
|
+
grouped += ",";
|
|
4142
|
+
}
|
|
4143
|
+
grouped += digits[i];
|
|
4144
|
+
}
|
|
4145
|
+
return negative ? `-${grouped}` : grouped;
|
|
4146
|
+
}
|
|
4147
|
+
function isoDate(iso) {
|
|
4148
|
+
return iso.slice(0, 10);
|
|
3678
4149
|
}
|
|
3679
4150
|
function confidenceBand(confidence, c) {
|
|
3680
4151
|
if (confidence === void 0) {
|
|
@@ -3689,25 +4160,56 @@ function confidenceBand(confidence, c) {
|
|
|
3689
4160
|
}
|
|
3690
4161
|
return lines;
|
|
3691
4162
|
}
|
|
3692
|
-
function
|
|
4163
|
+
function metricsSection(analysis, explanations, c) {
|
|
3693
4164
|
if (analysis.metrics.length === 0) {
|
|
3694
4165
|
return c.dim("No metrics computed.");
|
|
3695
4166
|
}
|
|
3696
|
-
const
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
4167
|
+
const present = GROUPS.filter((group) => analysis.metrics.some((metric) => metric.group === group.id));
|
|
4168
|
+
const sections = present.map((group) => {
|
|
4169
|
+
const metrics = analysis.metrics.filter((metric) => metric.group === group.id);
|
|
4170
|
+
const cards = metrics.map((metric) => metricCard(metric, explanations, c)).join("\n\n");
|
|
4171
|
+
return [c.bold(`${group.id} \xB7 ${group.title}`), c.dim(group.description), "", cards].join("\n");
|
|
4172
|
+
});
|
|
4173
|
+
return [c.bold("Metrics"), "", sections.join("\n\n")].join("\n");
|
|
4174
|
+
}
|
|
4175
|
+
function metricCard(metric, explanations, c) {
|
|
4176
|
+
const band = classifyHealth(metric);
|
|
4177
|
+
const heading = `${c.bold(metric.title)} ${healthTag(band, c)}`;
|
|
4178
|
+
const lines = [heading, valueBullet(metric, c)];
|
|
4179
|
+
const explanation = explanations?.[metric.id];
|
|
4180
|
+
if (explanation !== void 0) {
|
|
4181
|
+
lines.push(...facetBullets(explanation, c));
|
|
3707
4182
|
}
|
|
3708
4183
|
return lines.join("\n");
|
|
3709
4184
|
}
|
|
3710
|
-
function
|
|
4185
|
+
function healthTag(band, c) {
|
|
4186
|
+
const paintByBand = { ok: c.green, watch: c.yellow, risk: c.red, na: c.dim };
|
|
4187
|
+
return paintByBand[band](`${HEALTH_GLYPH[band]} ${HEALTH_LABEL[band]}`);
|
|
4188
|
+
}
|
|
4189
|
+
function valueBullet(metric, c) {
|
|
4190
|
+
const label = ` ${c.cyan("\u2022")} ${c.bold("Value")}`;
|
|
4191
|
+
if (metric.status !== "computed") {
|
|
4192
|
+
const reason = metric.reason === void 0 ? "" : ` \u2014 ${metric.reason}`;
|
|
4193
|
+
const note = `not available${reason}`;
|
|
4194
|
+
return `${label} \u2014 ${c.dim(note)}`;
|
|
4195
|
+
}
|
|
4196
|
+
return `${label} \u2014 ${formatValue2(metric.value)}`;
|
|
4197
|
+
}
|
|
4198
|
+
function facetBullets(explanation, c) {
|
|
4199
|
+
return [
|
|
4200
|
+
` ${c.cyan("\u2022")} ${c.bold("What it means")} \u2014 ${explanation.explanation}`,
|
|
4201
|
+
...arrayFacet("Strengths", explanation.goodBehaviours, c),
|
|
4202
|
+
...arrayFacet("Needs improvement", explanation.needsImprovement, c),
|
|
4203
|
+
...arrayFacet("Suggestions", explanation.suggestions, c)
|
|
4204
|
+
];
|
|
4205
|
+
}
|
|
4206
|
+
function arrayFacet(label, items, c) {
|
|
4207
|
+
if (items.length === 0) {
|
|
4208
|
+
return [` ${c.cyan("\u2022")} ${c.bold(label)} \u2014 \u2014`];
|
|
4209
|
+
}
|
|
4210
|
+
return [` ${c.cyan("\u2022")} ${c.bold(label)}`, ...items.map((item) => ` ${c.dim("-")} ${item}`)];
|
|
4211
|
+
}
|
|
4212
|
+
function formatValue2(value) {
|
|
3711
4213
|
if (value === void 0) {
|
|
3712
4214
|
return "";
|
|
3713
4215
|
}
|
|
@@ -3717,12 +4219,6 @@ function formatValue(value) {
|
|
|
3717
4219
|
}
|
|
3718
4220
|
return json.length > 60 ? `${json.slice(0, 59)}\u2026` : json;
|
|
3719
4221
|
}
|
|
3720
|
-
function maxWidth(values, floor) {
|
|
3721
|
-
return values.reduce((width, value) => Math.max(width, value.length), floor);
|
|
3722
|
-
}
|
|
3723
|
-
function pad2(value, width) {
|
|
3724
|
-
return value.length >= width ? value : value + " ".repeat(width - value.length);
|
|
3725
|
-
}
|
|
3726
4222
|
|
|
3727
4223
|
// src/render/html/escape.ts
|
|
3728
4224
|
function escapeHtml(text) {
|
|
@@ -3829,8 +4325,6 @@ function extractSeries(value) {
|
|
|
3829
4325
|
}
|
|
3830
4326
|
|
|
3831
4327
|
// src/render/html/svg.ts
|
|
3832
|
-
var VIEW_W = 100;
|
|
3833
|
-
var VIEW_H = 40;
|
|
3834
4328
|
function safe(n) {
|
|
3835
4329
|
return Number.isFinite(n) ? n : 0;
|
|
3836
4330
|
}
|
|
@@ -3840,99 +4334,265 @@ function r(n) {
|
|
|
3840
4334
|
function esc(text) {
|
|
3841
4335
|
return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
3842
4336
|
}
|
|
3843
|
-
function
|
|
3844
|
-
|
|
3845
|
-
|
|
4337
|
+
function hashId(text) {
|
|
4338
|
+
let h = 2166136261;
|
|
4339
|
+
for (let i = 0; i < text.length; i++) {
|
|
4340
|
+
h ^= text.charCodeAt(i);
|
|
4341
|
+
h = Math.imul(h, 16777619);
|
|
3846
4342
|
}
|
|
3847
|
-
|
|
3848
|
-
|
|
4343
|
+
return (h >>> 0).toString(36);
|
|
4344
|
+
}
|
|
4345
|
+
function maxValue(values) {
|
|
4346
|
+
let max = 0;
|
|
3849
4347
|
for (const raw of values) {
|
|
3850
4348
|
const v = safe(raw);
|
|
3851
|
-
if (v < min) min = v;
|
|
3852
4349
|
if (v > max) max = v;
|
|
3853
4350
|
}
|
|
3854
|
-
return
|
|
4351
|
+
return max;
|
|
3855
4352
|
}
|
|
3856
|
-
function
|
|
3857
|
-
|
|
4353
|
+
function fmtNum(v) {
|
|
4354
|
+
if (!Number.isFinite(v)) return "0";
|
|
4355
|
+
return Number.isInteger(v) ? String(v) : String(Math.round(v * 100) / 100);
|
|
4356
|
+
}
|
|
4357
|
+
var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
4358
|
+
function tickLabel(raw) {
|
|
4359
|
+
const month = /^(\d{4})-(\d{2})$/.exec(raw);
|
|
4360
|
+
if (month) {
|
|
4361
|
+
const mi = Number(month[2]);
|
|
4362
|
+
if (mi >= 1 && mi <= 12) return MONTHS[mi - 1];
|
|
4363
|
+
}
|
|
4364
|
+
const week = /^(\d{4})-W(\d{2})$/.exec(raw);
|
|
4365
|
+
if (week) return `W${week[2]}`;
|
|
4366
|
+
const slash = raw.lastIndexOf("/");
|
|
4367
|
+
const base = slash >= 0 ? raw.slice(slash + 1) : raw;
|
|
4368
|
+
return base.length > 16 ? `${base.slice(0, 15)}\u2026` : base;
|
|
4369
|
+
}
|
|
4370
|
+
function niceStep(range, n) {
|
|
4371
|
+
if (range <= 0) return 1;
|
|
4372
|
+
const raw = range / n;
|
|
4373
|
+
const exp = Math.floor(Math.log10(raw));
|
|
4374
|
+
const f = raw / 10 ** exp;
|
|
4375
|
+
const nf = f < 1.5 ? 1 : f < 3 ? 2 : f < 7 ? 5 : 10;
|
|
4376
|
+
return nf * 10 ** exp;
|
|
4377
|
+
}
|
|
4378
|
+
function valueTicks(max) {
|
|
4379
|
+
const m = max <= 0 ? 1 : max;
|
|
4380
|
+
const step = niceStep(m, 4);
|
|
4381
|
+
const top = Math.max(step, Math.ceil(m / step) * step);
|
|
4382
|
+
const ticks = [];
|
|
4383
|
+
for (let v = 0; v <= top + step / 1e3; v += step) {
|
|
4384
|
+
ticks.push(Math.round(v * 1e3) / 1e3);
|
|
4385
|
+
}
|
|
4386
|
+
return { ticks, top };
|
|
4387
|
+
}
|
|
4388
|
+
function open(label, extraClass, viewBox, par = "xMidYMid meet") {
|
|
4389
|
+
return `<svg class="chart-svg ${extraClass}" viewBox="${viewBox}" preserveAspectRatio="${par}" role="img" aria-label="${esc(label)}">`;
|
|
3858
4390
|
}
|
|
3859
4391
|
function empty(label, extraClass) {
|
|
3860
|
-
return `${open(label, extraClass)}</svg>`;
|
|
3861
|
-
}
|
|
3862
|
-
function
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
4392
|
+
return `${open(label, extraClass, "0 0 640 240")}</svg>`;
|
|
4393
|
+
}
|
|
4394
|
+
function areaGradient(id) {
|
|
4395
|
+
return `<defs><linearGradient id="${id}" x1="0" y1="0" x2="0" y2="1"><stop offset="0" class="grad-area-top"/><stop offset="1" class="grad-area-bottom"/></linearGradient></defs>`;
|
|
4396
|
+
}
|
|
4397
|
+
function fillGradient(id, vertical) {
|
|
4398
|
+
const dir = vertical ? `x1="0" y1="0" x2="0" y2="1"` : `x1="0" y1="0" x2="1" y2="0"`;
|
|
4399
|
+
return `<defs><linearGradient id="${id}" ${dir}><stop offset="0" class="grad-fill-1"/><stop offset="1" class="grad-fill-2"/></linearGradient></defs>`;
|
|
4400
|
+
}
|
|
4401
|
+
function smoothPath(coords) {
|
|
4402
|
+
if (coords.length === 1) {
|
|
4403
|
+
const [x, y] = coords[0];
|
|
4404
|
+
return `M ${r(x)} ${r(y)}`;
|
|
4405
|
+
}
|
|
4406
|
+
let d = `M ${r(coords[0][0])} ${r(coords[0][1])}`;
|
|
4407
|
+
for (let i = 0; i < coords.length - 1; i++) {
|
|
4408
|
+
const p0 = coords[i === 0 ? 0 : i - 1];
|
|
4409
|
+
const p1 = coords[i];
|
|
4410
|
+
const p2 = coords[i + 1];
|
|
4411
|
+
const p3 = coords[i + 2 < coords.length ? i + 2 : coords.length - 1];
|
|
4412
|
+
const c1x = p1[0] + (p2[0] - p0[0]) / 6;
|
|
4413
|
+
const c1y = p1[1] + (p2[1] - p0[1]) / 6;
|
|
4414
|
+
const c2x = p2[0] - (p3[0] - p1[0]) / 6;
|
|
4415
|
+
const c2y = p2[1] - (p3[1] - p1[1]) / 6;
|
|
4416
|
+
d += ` C ${r(c1x)} ${r(c1y)}, ${r(c2x)} ${r(c2y)}, ${r(p2[0])} ${r(p2[1])}`;
|
|
4417
|
+
}
|
|
4418
|
+
return d;
|
|
4419
|
+
}
|
|
4420
|
+
function roundedTopRect(x, y, w, h, rad, gradId) {
|
|
4421
|
+
if (h <= 0 || w <= 0) return "";
|
|
4422
|
+
const k = Math.min(rad, w / 2, h);
|
|
4423
|
+
const d = `M ${r(x)} ${r(y + h)} L ${r(x)} ${r(y + k)} Q ${r(x)} ${r(y)} ${r(x + k)} ${r(y)} L ${r(x + w - k)} ${r(y)} Q ${r(x + w)} ${r(y)} ${r(x + w)} ${r(y + k)} L ${r(x + w)} ${r(y + h)} Z`;
|
|
4424
|
+
return `<path class="bar" d="${d}" fill="url(#${gradId})"/>`;
|
|
4425
|
+
}
|
|
4426
|
+
function roundedRightRect(x, y, w, h, rad, gradId) {
|
|
4427
|
+
if (h <= 0 || w <= 0) return "";
|
|
4428
|
+
const k = Math.min(rad, h / 2, w);
|
|
4429
|
+
const d = `M ${r(x)} ${r(y)} L ${r(x + w - k)} ${r(y)} Q ${r(x + w)} ${r(y)} ${r(x + w)} ${r(y + k)} L ${r(x + w)} ${r(y + h - k)} Q ${r(x + w)} ${r(y + h)} ${r(x + w - k)} ${r(y + h)} L ${r(x)} ${r(y + h)} Z`;
|
|
4430
|
+
return `<path class="bar" d="${d}" fill="url(#${gradId})"/>`;
|
|
4431
|
+
}
|
|
4432
|
+
function valueGrid(ticks, top, x0, x1, y0, y1) {
|
|
4433
|
+
return ticks.map((t) => {
|
|
4434
|
+
const y = r(y1 - t / top * (y1 - y0));
|
|
4435
|
+
return `<line class="chart-grid" x1="${x0}" y1="${y}" x2="${x1}" y2="${y}"/><text class="chart-tick" x="${x0 - 6}" y="${r(y + 3.5)}" text-anchor="end">${esc(fmtNum(t))}</text>`;
|
|
4436
|
+
}).join("");
|
|
3869
4437
|
}
|
|
3870
4438
|
function svgLine(series, label) {
|
|
3871
|
-
if (series.length === 0)
|
|
3872
|
-
|
|
3873
|
-
}
|
|
3874
|
-
const
|
|
3875
|
-
const
|
|
3876
|
-
const
|
|
3877
|
-
const
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
4439
|
+
if (series.length === 0) return empty(label, "chart-line");
|
|
4440
|
+
const id = hashId(label);
|
|
4441
|
+
const areaId = `cw-area-${id}`;
|
|
4442
|
+
const strokeId = `cw-stroke-${id}`;
|
|
4443
|
+
const W = 640;
|
|
4444
|
+
const H = 240;
|
|
4445
|
+
const mL = 46;
|
|
4446
|
+
const mR = 16;
|
|
4447
|
+
const mT = 14;
|
|
4448
|
+
const mB = 30;
|
|
4449
|
+
const x0 = mL;
|
|
4450
|
+
const x1 = W - mR;
|
|
4451
|
+
const y0 = mT;
|
|
4452
|
+
const y1 = H - mB;
|
|
4453
|
+
const { ticks, top } = valueTicks(maxValue(series.map((p) => p.value)));
|
|
4454
|
+
const xAt = (i) => series.length === 1 ? (x0 + x1) / 2 : x0 + i / (series.length - 1) * (x1 - x0);
|
|
4455
|
+
const yAt = (v) => y1 - Math.max(0, safe(v)) / top * (y1 - y0);
|
|
4456
|
+
const coords = series.map((p, i) => [r(xAt(i)), r(yAt(p.value))]);
|
|
4457
|
+
const line = smoothPath(coords);
|
|
4458
|
+
const area = `${line} L ${r(coords[coords.length - 1][0])} ${y1} L ${r(coords[0][0])} ${y1} Z`;
|
|
4459
|
+
const every = series.length > 12 ? Math.ceil(series.length / 12) : 1;
|
|
4460
|
+
const xLabels = series.map((p, i) => i % every === 0 ? `<text class="chart-label" x="${r(xAt(i))}" y="${H - 10}" text-anchor="middle">${esc(tickLabel(p.label))}</text>` : "").join("");
|
|
4461
|
+
const dot = coords.length === 1 ? `<circle class="chart-dot" cx="${r(coords[0][0])}" cy="${r(coords[0][1])}" r="4"/>` : "";
|
|
4462
|
+
return `${open(label, "chart-line", `0 0 ${W} ${H}`)}${areaGradient(areaId)}${fillGradient(strokeId, false)}${valueGrid(ticks, top, x0, x1, y0, y1)}<line class="chart-axis" x1="${x0}" y1="${y1}" x2="${x1}" y2="${y1}"/><path class="chart-area" d="${area}" fill="url(#${areaId})"/><path class="chart-stroke" d="${line}" fill="none" stroke="url(#${strokeId})" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round"/>${dot}${xLabels}</svg>`;
|
|
3882
4463
|
}
|
|
3883
4464
|
function svgBars(series, label) {
|
|
3884
|
-
if (series.length === 0)
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
const
|
|
3888
|
-
const
|
|
3889
|
-
const
|
|
3890
|
-
const
|
|
3891
|
-
const
|
|
4465
|
+
if (series.length === 0) return empty(label, "chart-bars");
|
|
4466
|
+
const id = `cw-bar-${hashId(label)}`;
|
|
4467
|
+
const W = 640;
|
|
4468
|
+
const H = 240;
|
|
4469
|
+
const mL = 46;
|
|
4470
|
+
const mR = 16;
|
|
4471
|
+
const mT = 14;
|
|
4472
|
+
const mB = 30;
|
|
4473
|
+
const x0 = mL;
|
|
4474
|
+
const x1 = W - mR;
|
|
4475
|
+
const y0 = mT;
|
|
4476
|
+
const y1 = H - mB;
|
|
4477
|
+
const { ticks, top } = valueTicks(maxValue(series.map((p) => p.value)));
|
|
4478
|
+
const slot = (x1 - x0) / series.length;
|
|
4479
|
+
const barW = Math.min(slot * 0.62, 64);
|
|
4480
|
+
const rad = Math.min(barW / 2, 6);
|
|
3892
4481
|
const bars = series.map((p, i) => {
|
|
3893
|
-
const h = Math.max(0, safe(p.value)) / top * (
|
|
3894
|
-
const x = i * slot + (slot - barW) / 2;
|
|
3895
|
-
|
|
3896
|
-
return `<rect class="bar" x="${r(x)}" y="${r(y)}" width="${r(barW)}" height="${r(h)}"/>`;
|
|
4482
|
+
const h = Math.max(0, safe(p.value)) / top * (y1 - y0);
|
|
4483
|
+
const x = x0 + i * slot + (slot - barW) / 2;
|
|
4484
|
+
return roundedTopRect(x, y1 - h, barW, h, rad, id);
|
|
3897
4485
|
}).join("");
|
|
3898
|
-
|
|
4486
|
+
const xLabels = series.map((p, i) => `<text class="chart-label" x="${r(x0 + i * slot + slot / 2)}" y="${H - 10}" text-anchor="middle">${esc(tickLabel(p.label))}</text>`).join("");
|
|
4487
|
+
return `${open(label, "chart-bars", `0 0 ${W} ${H}`)}${fillGradient(id, true)}${valueGrid(ticks, top, x0, x1, y0, y1)}<line class="chart-axis" x1="${x0}" y1="${y1}" x2="${x1}" y2="${y1}"/>${bars}${xLabels}</svg>`;
|
|
3899
4488
|
}
|
|
3900
4489
|
function svgHBars(series, label) {
|
|
3901
|
-
if (series.length === 0)
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
const
|
|
3905
|
-
const
|
|
3906
|
-
const
|
|
3907
|
-
const
|
|
3908
|
-
const
|
|
4490
|
+
if (series.length === 0) return empty(label, "chart-hbars");
|
|
4491
|
+
const id = `cw-hbar-${hashId(label)}`;
|
|
4492
|
+
const n = series.length;
|
|
4493
|
+
const rowH = 30;
|
|
4494
|
+
const mL = 150;
|
|
4495
|
+
const mR = 22;
|
|
4496
|
+
const mT = 14;
|
|
4497
|
+
const mB = 30;
|
|
4498
|
+
const W = 640;
|
|
4499
|
+
const H = mT + n * rowH + mB;
|
|
4500
|
+
const x0 = mL;
|
|
4501
|
+
const x1 = W - mR;
|
|
4502
|
+
const y0 = mT;
|
|
4503
|
+
const y1 = H - mB;
|
|
4504
|
+
const { ticks, top } = valueTicks(maxValue(series.map((p) => p.value)));
|
|
4505
|
+
const grid = ticks.map((t) => {
|
|
4506
|
+
const x = r(x0 + t / top * (x1 - x0));
|
|
4507
|
+
return `<line class="chart-grid" x1="${x}" y1="${y0}" x2="${x}" y2="${y1}"/><text class="chart-tick" x="${x}" y="${H - 10}" text-anchor="middle">${esc(fmtNum(t))}</text>`;
|
|
4508
|
+
}).join("");
|
|
4509
|
+
const barH = rowH * 0.6;
|
|
3909
4510
|
const bars = series.map((p, i) => {
|
|
3910
|
-
const w = Math.max(0, safe(p.value)) / top *
|
|
3911
|
-
const y = i *
|
|
3912
|
-
return
|
|
4511
|
+
const w = Math.max(0, safe(p.value)) / top * (x1 - x0);
|
|
4512
|
+
const y = y0 + i * rowH + (rowH - barH) / 2;
|
|
4513
|
+
return roundedRightRect(x0, y, w, barH, Math.min(barH / 2, 5), id);
|
|
3913
4514
|
}).join("");
|
|
3914
|
-
|
|
3915
|
-
}
|
|
3916
|
-
function svgGauge(value, max, label) {
|
|
3917
|
-
const denom = max <= 0 ? 1 : max;
|
|
3918
|
-
const t = Math.min(1, Math.max(0, safe(value) / denom));
|
|
3919
|
-
return `${open(label, "chart-gauge")}<rect class="gauge-track" x="0" y="${r(VIEW_H / 2 - 4)}" width="${VIEW_W}" height="8" rx="4"/><rect class="gauge-fill" x="0" y="${r(VIEW_H / 2 - 4)}" width="${r(t * VIEW_W)}" height="8" rx="4"/></svg>`;
|
|
4515
|
+
const yLabels = series.map((p, i) => `<text class="chart-label" x="${x0 - 8}" y="${r(y0 + i * rowH + rowH / 2 + 3.5)}" text-anchor="end">${esc(tickLabel(p.label))}</text>`).join("");
|
|
4516
|
+
return `${open(label, "chart-hbars", `0 0 ${W} ${H}`)}${fillGradient(id, false)}${grid}<line class="chart-axis" x1="${x0}" y1="${y0}" x2="${x0}" y2="${y1}"/>${bars}${yLabels}</svg>`;
|
|
3920
4517
|
}
|
|
3921
4518
|
function svgRadar(points, max, label) {
|
|
3922
4519
|
if (points.length < 3) {
|
|
3923
4520
|
return svgBars(points, label).replace("chart-bars", "chart-radar");
|
|
3924
4521
|
}
|
|
4522
|
+
const id = `cw-radar-${hashId(label)}`;
|
|
3925
4523
|
const denom = max <= 0 ? 1 : max;
|
|
3926
|
-
const
|
|
3927
|
-
const
|
|
3928
|
-
const
|
|
4524
|
+
const W = 300;
|
|
4525
|
+
const H = 230;
|
|
4526
|
+
const cx = W / 2;
|
|
4527
|
+
const cy = 108;
|
|
4528
|
+
const radius = 72;
|
|
3929
4529
|
const n = points.length;
|
|
3930
|
-
const
|
|
4530
|
+
const angle = (i) => Math.PI * 2 * i / n - Math.PI / 2;
|
|
4531
|
+
const ringFor = (factor) => {
|
|
4532
|
+
const pts = points.map((_, i) => `${r(cx + Math.cos(angle(i)) * radius * factor)},${r(cy + Math.sin(angle(i)) * radius * factor)}`).join(" ");
|
|
4533
|
+
return `<polygon class="radar-grid" points="${pts}"/>`;
|
|
4534
|
+
};
|
|
4535
|
+
const rings = [0.25, 0.5, 0.75, 1].map(ringFor).join("");
|
|
4536
|
+
const axes = points.map((_, i) => `<line class="radar-axis" x1="${cx}" y1="${cy}" x2="${r(cx + Math.cos(angle(i)) * radius)}" y2="${r(cy + Math.sin(angle(i)) * radius)}"/>`).join("");
|
|
4537
|
+
const dataCoords = points.map((p, i) => {
|
|
3931
4538
|
const t = Math.min(1, Math.max(0, safe(p.value) / denom));
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
}).join(" ");
|
|
3935
|
-
|
|
4539
|
+
return [r(cx + Math.cos(angle(i)) * radius * t), r(cy + Math.sin(angle(i)) * radius * t)];
|
|
4540
|
+
});
|
|
4541
|
+
const dataPts = dataCoords.map(([x, y]) => `${x},${y}`).join(" ");
|
|
4542
|
+
const dots = dataCoords.map(([x, y]) => `<circle class="radar-dot" cx="${x}" cy="${y}" r="2.4"/>`).join("");
|
|
4543
|
+
const labels = points.map((p, i) => {
|
|
4544
|
+
const lx = cx + Math.cos(angle(i)) * (radius + 16);
|
|
4545
|
+
const ly = cy + Math.sin(angle(i)) * (radius + 16);
|
|
4546
|
+
const anchor = lx > cx + 1 ? "start" : lx < cx - 1 ? "end" : "middle";
|
|
4547
|
+
const name = p.label.length > 12 ? `${p.label.slice(0, 11)}\u2026` : p.label;
|
|
4548
|
+
return `<text class="radar-label" x="${r(lx)}" y="${r(ly + 3)}" text-anchor="${anchor}">${esc(name)}</text>`;
|
|
4549
|
+
}).join("");
|
|
4550
|
+
return `${open(label, "chart-radar", `0 0 ${W} ${H}`)}${fillGradient(id, true)}${rings}${axes}<polygon class="radar-area" points="${dataPts}" fill="url(#${id})"/>${dots}${labels}</svg>`;
|
|
4551
|
+
}
|
|
4552
|
+
function svgRadialGauge(value, max, label) {
|
|
4553
|
+
const id = `cw-rgauge-${hashId(label)}`;
|
|
4554
|
+
const denom = max <= 0 ? 1 : max;
|
|
4555
|
+
const t = Math.min(1, Math.max(0, safe(value) / denom));
|
|
4556
|
+
const cx = 100;
|
|
4557
|
+
const cy = 100;
|
|
4558
|
+
const rr = 74;
|
|
4559
|
+
const circ = 2 * Math.PI * rr;
|
|
4560
|
+
const dash = r(t * circ);
|
|
4561
|
+
const center = `${fmtNum(Math.round(safe(value) * 100) / 100)}${max === 100 ? "%" : ""}`;
|
|
4562
|
+
return `${open(label, "chart-radialgauge", "0 0 200 200")}${fillGradient(id, false)}<circle class="gauge-ring-track" cx="${cx}" cy="${cy}" r="${rr}" fill="none" stroke-width="20"/><circle class="gauge-ring-fill" cx="${cx}" cy="${cy}" r="${rr}" fill="none" stroke="url(#${id})" stroke-width="20" stroke-linecap="round" stroke-dasharray="${dash} ${r(circ)}" transform="rotate(-90 ${cx} ${cy})"/><text class="gauge-value" x="${cx}" y="${cy}" text-anchor="middle" dominant-baseline="central">${esc(center)}</text></svg>`;
|
|
4563
|
+
}
|
|
4564
|
+
function svgDonut(series, label) {
|
|
4565
|
+
if (series.length === 0) return empty(label, "chart-donut");
|
|
4566
|
+
const total = series.reduce((sum, p) => sum + Math.max(0, safe(p.value)), 0);
|
|
4567
|
+
if (total <= 0) return empty(label, "chart-donut");
|
|
4568
|
+
const cx = 100;
|
|
4569
|
+
const cy = 100;
|
|
4570
|
+
const rOuter = 82;
|
|
4571
|
+
const rInner = 50;
|
|
4572
|
+
let cum = 0;
|
|
4573
|
+
const segments = series.map((p, i) => {
|
|
4574
|
+
const frac = Math.max(0, safe(p.value)) / total;
|
|
4575
|
+
const a0 = (-90 + cum * 360) * Math.PI / 180;
|
|
4576
|
+
const a1 = (-90 + (cum + frac) * 360) * Math.PI / 180;
|
|
4577
|
+
cum += frac;
|
|
4578
|
+
const large = frac > 0.5 ? 1 : 0;
|
|
4579
|
+
const x0o = r(cx + rOuter * Math.cos(a0));
|
|
4580
|
+
const y0o = r(cy + rOuter * Math.sin(a0));
|
|
4581
|
+
const x1o = r(cx + rOuter * Math.cos(a1));
|
|
4582
|
+
const y1o = r(cy + rOuter * Math.sin(a1));
|
|
4583
|
+
const x1i = r(cx + rInner * Math.cos(a1));
|
|
4584
|
+
const y1i = r(cy + rInner * Math.sin(a1));
|
|
4585
|
+
const x0i = r(cx + rInner * Math.cos(a0));
|
|
4586
|
+
const y0i = r(cy + rInner * Math.sin(a0));
|
|
4587
|
+
const d = `M ${x0o} ${y0o} A ${rOuter} ${rOuter} 0 ${large} 1 ${x1o} ${y1o} L ${x1i} ${y1i} A ${rInner} ${rInner} 0 ${large} 0 ${x0i} ${y0i} Z`;
|
|
4588
|
+
return `<path class="donut-seg slice-${i % 6}" d="${d}"/>`;
|
|
4589
|
+
}).join("");
|
|
4590
|
+
const legend = series.map((p, i) => {
|
|
4591
|
+
const pct2 = Math.round(Math.max(0, safe(p.value)) / total * 100);
|
|
4592
|
+
const y = 44 + i * 24;
|
|
4593
|
+
return `<rect class="slice-${i % 6}" x="200" y="${y}" width="13" height="13" rx="3"/><text class="donut-label" x="220" y="${y + 11}">${esc(tickLabel(p.label))} \xB7 ${pct2}%</text>`;
|
|
4594
|
+
}).join("");
|
|
4595
|
+
return `${open(label, "chart-donut", "0 0 360 200")}${segments}${legend}</svg>`;
|
|
3936
4596
|
}
|
|
3937
4597
|
|
|
3938
4598
|
// src/render/html/charts.ts
|
|
@@ -3963,151 +4623,74 @@ function formatNumber(value) {
|
|
|
3963
4623
|
}
|
|
3964
4624
|
return Number.isInteger(value) ? String(value) : String(Math.round(value * 100) / 100);
|
|
3965
4625
|
}
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
4626
|
+
var GROUP_CHARTS = {
|
|
4627
|
+
A: [{ kind: "line", pick: "timeseries", index: 0 }, { kind: "bars", pick: "timeseries", index: 1 }],
|
|
4628
|
+
B: [{ kind: "donut", pick: "distribution", index: 0 }, { kind: "gauge", pick: "range", index: 0 }],
|
|
4629
|
+
C: [{ kind: "bars", pick: "distribution", index: 0 }, { kind: "gauge", pick: "range", index: 0 }],
|
|
4630
|
+
D: [{ kind: "line", pick: "timeseries", index: 0 }, { kind: "gauge", pick: "range", index: 0 }],
|
|
4631
|
+
E: [{ kind: "hbars", pick: "distribution", index: 0 }, { kind: "line", pick: "timeseries", index: 0 }],
|
|
4632
|
+
F: [{ kind: "radar", pick: "distribution", index: 0 }, { kind: "gauge", pick: "range", index: 0 }]
|
|
4633
|
+
};
|
|
4634
|
+
function metricsOfShape(metrics, shape) {
|
|
4635
|
+
return metrics.filter((m) => m.status === "computed" && detectShape(m.value) === shape && extractSeries(m.value).length > 0);
|
|
4636
|
+
}
|
|
4637
|
+
function rangeMetrics(metrics) {
|
|
4638
|
+
return metrics.filter((m) => m.status === "computed" && rangeField(m.value) !== void 0);
|
|
4639
|
+
}
|
|
4640
|
+
function subFigure(title2, svg, table) {
|
|
4641
|
+
return `<div class="chart-sub">
|
|
4642
|
+
<h4>${escapeHtml(title2)}</h4>
|
|
4643
|
+
${svg}
|
|
4644
|
+
${table}
|
|
4645
|
+
</div>`;
|
|
4646
|
+
}
|
|
4647
|
+
function renderSubChart(group, spec, metrics) {
|
|
4648
|
+
const pool = spec.pick === "range" ? rangeMetrics(metrics) : metricsOfShape(metrics, spec.pick);
|
|
4649
|
+
const metric = pool[spec.index];
|
|
4650
|
+
if (metric === void 0) {
|
|
4651
|
+
return void 0;
|
|
3979
4652
|
}
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
case "E":
|
|
3989
|
-
return svgHBars(series, label);
|
|
3990
|
-
case "C":
|
|
3991
|
-
return svgBars(series, label);
|
|
3992
|
-
case "F":
|
|
3993
|
-
return svgRadar(series, 100, label);
|
|
3994
|
-
default:
|
|
3995
|
-
return svgBars(series, label);
|
|
4653
|
+
const label = `Group ${group} \u2014 ${metric.title}`;
|
|
4654
|
+
if (spec.kind === "gauge") {
|
|
4655
|
+
const range = rangeField(metric.value);
|
|
4656
|
+
if (range === void 0) {
|
|
4657
|
+
return void 0;
|
|
4658
|
+
}
|
|
4659
|
+
const table = dataTable([{ label: metric.title, value: range.value }], "Value", metric.title);
|
|
4660
|
+
return subFigure(metric.title, svgRadialGauge(range.value, range.max, label), table);
|
|
3996
4661
|
}
|
|
4662
|
+
const series = extractSeries(metric.value);
|
|
4663
|
+
const svg = spec.kind === "line" ? svgLine(series, label) : spec.kind === "bars" ? svgBars(series, label) : spec.kind === "hbars" ? svgHBars(series, label) : spec.kind === "radar" ? svgRadar(series, 100, label) : svgDonut(series, label);
|
|
4664
|
+
return subFigure(metric.title, svg, dataTable(series, "Value", metric.title));
|
|
3997
4665
|
}
|
|
3998
4666
|
function groupOverviewPanel(group, metrics) {
|
|
3999
4667
|
const description = GROUP_DESCRIPTION[group];
|
|
4000
|
-
const
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
return `<figure class="chart-panel" aria-label="${escapeHtml(
|
|
4668
|
+
const label = `Group ${group} overview`;
|
|
4669
|
+
const subs = GROUP_CHARTS[group].map((spec) => renderSubChart(group, spec, metrics)).filter((html) => html !== void 0);
|
|
4670
|
+
if (subs.length === 0) {
|
|
4671
|
+
return `<figure class="chart-panel" aria-label="${escapeHtml(label)}">
|
|
4004
4672
|
<figcaption>${escapeHtml(description)}</figcaption>
|
|
4005
4673
|
<p class="chart-empty">No chartable series for this group \u2014 see the metric cards below.</p>
|
|
4006
4674
|
</figure>`;
|
|
4007
4675
|
}
|
|
4008
|
-
const
|
|
4676
|
+
const gridClass = subs.length > 1 ? "chart-cells two" : "chart-cells";
|
|
4009
4677
|
return `<figure class="chart-panel" aria-label="${escapeHtml(label)}">
|
|
4010
|
-
<figcaption>${escapeHtml(description)}
|
|
4011
|
-
${
|
|
4012
|
-
${
|
|
4678
|
+
<figcaption>${escapeHtml(description)}</figcaption>
|
|
4679
|
+
<div class="${gridClass}">
|
|
4680
|
+
${subs.join("\n")}
|
|
4681
|
+
</div>
|
|
4013
4682
|
</figure>`;
|
|
4014
4683
|
}
|
|
4015
|
-
function metricVisual(metric) {
|
|
4016
|
-
if (metric.status === "not_available") {
|
|
4017
|
-
return "";
|
|
4018
|
-
}
|
|
4019
|
-
const label = `${metric.title} visual`;
|
|
4020
|
-
const shape = detectShape(metric.value);
|
|
4021
|
-
switch (shape) {
|
|
4022
|
-
case "timeseries": {
|
|
4023
|
-
const series = extractSeries(metric.value);
|
|
4024
|
-
return `<div class="metric-visual">${svgLine(series, label)}
|
|
4025
|
-
${dataTable(series, "Value", metric.title)}</div>`;
|
|
4026
|
-
}
|
|
4027
|
-
case "distribution": {
|
|
4028
|
-
const series = extractSeries(metric.value);
|
|
4029
|
-
return `<div class="metric-visual">${svgBars(series, label)}
|
|
4030
|
-
${dataTable(series, "Value", metric.title)}</div>`;
|
|
4031
|
-
}
|
|
4032
|
-
case "scalar-range": {
|
|
4033
|
-
const range = rangeField(metric.value);
|
|
4034
|
-
const series = extractSeries(metric.value);
|
|
4035
|
-
const gauge = range === void 0 ? "" : svgGauge(range.value, range.max, label);
|
|
4036
|
-
const spark = series.length > 1 ? svgSparkline(series, label) : "";
|
|
4037
|
-
const number = range === void 0 ? "" : `<span class="metric-number">${escapeHtml(formatNumber(range.value))}</span>`;
|
|
4038
|
-
return `<div class="metric-visual metric-visual-range">${gauge}${spark}${number}
|
|
4039
|
-
${dataTable(series, "Value", metric.title)}</div>`;
|
|
4040
|
-
}
|
|
4041
|
-
case "scalar":
|
|
4042
|
-
case "none":
|
|
4043
|
-
default:
|
|
4044
|
-
return "";
|
|
4045
|
-
}
|
|
4046
|
-
}
|
|
4047
4684
|
|
|
4048
|
-
// src/render/html/
|
|
4049
|
-
var HEALTH_GLYPH = {
|
|
4050
|
-
ok: "\u25CF",
|
|
4051
|
-
watch: "\u25D0",
|
|
4052
|
-
risk: "\u25B2",
|
|
4053
|
-
|
|
4054
|
-
};
|
|
4055
|
-
var HEALTH_LABEL = {
|
|
4056
|
-
ok: "ok",
|
|
4057
|
-
watch: "watch",
|
|
4058
|
-
risk: "risk",
|
|
4059
|
-
na: "n/a"
|
|
4060
|
-
};
|
|
4061
|
-
function field(value, key) {
|
|
4062
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4063
|
-
return void 0;
|
|
4064
|
-
}
|
|
4065
|
-
const v = value[key];
|
|
4066
|
-
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
4067
|
-
}
|
|
4068
|
-
function higherBetter(key, okMin, watchMin) {
|
|
4069
|
-
return (value) => {
|
|
4070
|
-
const n = field(value, key);
|
|
4071
|
-
if (n === void 0) return "ok";
|
|
4072
|
-
if (n >= okMin) return "ok";
|
|
4073
|
-
if (n >= watchMin) return "watch";
|
|
4074
|
-
return "risk";
|
|
4075
|
-
};
|
|
4076
|
-
}
|
|
4077
|
-
function lowerBetter(key, okMax, watchMax) {
|
|
4078
|
-
return (value) => {
|
|
4079
|
-
const n = field(value, key);
|
|
4080
|
-
if (n === void 0) return "ok";
|
|
4081
|
-
if (n <= okMax) return "ok";
|
|
4082
|
-
if (n <= watchMax) return "watch";
|
|
4083
|
-
return "risk";
|
|
4084
|
-
};
|
|
4085
|
-
}
|
|
4086
|
-
var REGISTRY = {
|
|
4087
|
-
// Knowledge concentration — fewer key people is riskier.
|
|
4088
|
-
"b-bus-factor": higherBetter("busFactor", 3, 2),
|
|
4089
|
-
"f-bus-factor-risk": higherBetter("busFactor", 3, 2),
|
|
4090
|
-
// Contribution concentration — a very high top share concentrates load.
|
|
4091
|
-
"b-contribution-distribution": lowerBetter("topCommitSharePct", 60, 80),
|
|
4092
|
-
// Message quality — higher Conventional-Commits adherence is healthier.
|
|
4093
|
-
"c-conventional-commits": higherBetter("adherenceSharePct", 70, 40),
|
|
4094
|
-
// Low-information commit messages — fewer is healthier.
|
|
4095
|
-
"c-low-information-rate": lowerBetter("lowInfoSharePct", 10, 25),
|
|
4096
|
-
// Workflow discipline — a high direct-to-default share is riskier.
|
|
4097
|
-
"d-direct-to-default": lowerBetter("directToDefaultSharePct", 20, 50),
|
|
4098
|
-
// Overall hygiene composite (0–100).
|
|
4099
|
-
"f-hygiene-score": higherBetter("score", 75, 50)
|
|
4100
|
-
};
|
|
4101
|
-
function classifyHealth(metric) {
|
|
4102
|
-
if (metric.status === "not_available") {
|
|
4103
|
-
return "na";
|
|
4104
|
-
}
|
|
4105
|
-
const classifier = REGISTRY[metric.id];
|
|
4106
|
-
return classifier === void 0 ? "ok" : classifier(metric.value);
|
|
4107
|
-
}
|
|
4685
|
+
// src/render/html/inter-font.ts
|
|
4686
|
+
var INTER_FONT_CSS = `@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2');}
|
|
4687
|
+
@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2');}
|
|
4688
|
+
@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2');}
|
|
4689
|
+
@font-face{font-family:'Inter';font-style:normal;font-weight:800;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2');}
|
|
4690
|
+
`;
|
|
4108
4691
|
|
|
4109
4692
|
// src/render/html/html-renderer.ts
|
|
4110
|
-
var
|
|
4693
|
+
var GROUPS2 = [
|
|
4111
4694
|
{ id: "A", title: "Activity & Cadence" },
|
|
4112
4695
|
{ id: "B", title: "Contribution & Ownership" },
|
|
4113
4696
|
{ id: "C", title: "Commit Message Quality" },
|
|
@@ -4119,30 +4702,31 @@ var HTML_DEGRADED_BANNER = "\u26A0 Narrative unavailable \u2014 showing raw anal
|
|
|
4119
4702
|
var HTML_METRICS_ONLY_NOTE = "Metrics-only run \u2014 no AI narrative requested";
|
|
4120
4703
|
function renderHtml(report) {
|
|
4121
4704
|
const route = classifyReport(report);
|
|
4122
|
-
const
|
|
4123
|
-
|
|
4705
|
+
const provenance = report.provenance;
|
|
4706
|
+
const body = route.kind === "showpiece" ? renderShowpiece2(route.report, provenance) : renderSubstrate2(route.analysis, route.framing, provenance);
|
|
4707
|
+
return document(body, provenance);
|
|
4124
4708
|
}
|
|
4125
|
-
function document(body) {
|
|
4709
|
+
function document(body, provenance) {
|
|
4126
4710
|
return `<!doctype html>
|
|
4127
4711
|
<html lang="en">
|
|
4128
4712
|
<head>
|
|
4129
4713
|
<meta charset="utf-8">
|
|
4130
4714
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
4131
4715
|
<title>commit-whisper report</title>
|
|
4132
|
-
<style>${STYLE}</style>
|
|
4716
|
+
<style>${INTER_FONT_CSS}${STYLE}</style>
|
|
4133
4717
|
</head>
|
|
4134
4718
|
<body>
|
|
4135
4719
|
<a class="skip-link" href="#main">Skip to content</a>
|
|
4136
4720
|
${body}
|
|
4137
|
-
${footer()}
|
|
4721
|
+
${footer(provenance)}
|
|
4138
4722
|
<script>${DISCLOSURE_SCRIPT}</script>
|
|
4139
4723
|
</body>
|
|
4140
4724
|
</html>`;
|
|
4141
4725
|
}
|
|
4142
|
-
function renderShowpiece2(report) {
|
|
4726
|
+
function renderShowpiece2(report, provenance) {
|
|
4143
4727
|
const { summary, explanation, coaching, explanations, confidence } = report.narrative;
|
|
4144
4728
|
return [
|
|
4145
|
-
|
|
4729
|
+
masthead2(confidence, provenance),
|
|
4146
4730
|
summaryBand(summary),
|
|
4147
4731
|
toc(true, report.analysis),
|
|
4148
4732
|
explanationBand(explanation),
|
|
@@ -4150,17 +4734,63 @@ function renderShowpiece2(report) {
|
|
|
4150
4734
|
metricGroups(report.analysis, explanations)
|
|
4151
4735
|
].join("\n");
|
|
4152
4736
|
}
|
|
4153
|
-
function renderSubstrate2(analysis, framing) {
|
|
4154
|
-
return [
|
|
4155
|
-
}
|
|
4156
|
-
function
|
|
4157
|
-
const
|
|
4737
|
+
function renderSubstrate2(analysis, framing, provenance) {
|
|
4738
|
+
return [masthead2(void 0, provenance), substrateBanner(framing), toc(false, analysis), metricGroups(analysis, void 0)].join("\n");
|
|
4739
|
+
}
|
|
4740
|
+
function masthead2(confidence, provenance) {
|
|
4741
|
+
const parts = [
|
|
4742
|
+
"<h1>commit-whisper</h1>",
|
|
4743
|
+
`<p class="tagline">Deterministic git-history analysis with a grounded AI narrative.</p>`,
|
|
4744
|
+
provenanceChips2(provenance),
|
|
4745
|
+
capLine2(provenance),
|
|
4746
|
+
confidence === void 0 ? "" : confidenceBand2(confidence)
|
|
4747
|
+
].filter((part) => part !== "");
|
|
4158
4748
|
return `<header class="masthead">
|
|
4159
|
-
|
|
4160
|
-
<p class="tagline">Deterministic git-history analysis with a grounded AI narrative.</p>
|
|
4161
|
-
${band}
|
|
4749
|
+
${parts.join("\n")}
|
|
4162
4750
|
</header>`;
|
|
4163
4751
|
}
|
|
4752
|
+
function provenanceChips2(provenance) {
|
|
4753
|
+
const repo = provenance?.repo;
|
|
4754
|
+
const scale = provenance?.scale;
|
|
4755
|
+
const chips = [];
|
|
4756
|
+
if (repo?.name !== void 0) {
|
|
4757
|
+
chips.push(provChip(repo.name));
|
|
4758
|
+
}
|
|
4759
|
+
if (repo?.branch !== void 0) {
|
|
4760
|
+
chips.push(provChip(repo.branch));
|
|
4761
|
+
}
|
|
4762
|
+
const commits = scale?.totalCommits ?? scale?.analyzedCommits;
|
|
4763
|
+
if (commits !== void 0) {
|
|
4764
|
+
chips.push(provChip(`${formatCount2(commits)} ${commits === 1 ? "commit" : "commits"}`));
|
|
4765
|
+
}
|
|
4766
|
+
if (scale?.contributors !== void 0) {
|
|
4767
|
+
chips.push(provChip(`${formatCount2(scale.contributors)} ${scale.contributors === 1 ? "contributor" : "contributors"}`));
|
|
4768
|
+
}
|
|
4769
|
+
const generatedAt = provenance?.run?.generatedAt;
|
|
4770
|
+
if (generatedAt !== void 0) {
|
|
4771
|
+
chips.push(provChip(`analyzed ${isoDate2(generatedAt)}`));
|
|
4772
|
+
}
|
|
4773
|
+
if (chips.length === 0) {
|
|
4774
|
+
return "";
|
|
4775
|
+
}
|
|
4776
|
+
return `<p class="prov-chips">${chips.join('<span class="prov-sep" aria-hidden="true">\xB7</span>')}</p>`;
|
|
4777
|
+
}
|
|
4778
|
+
function provChip(text) {
|
|
4779
|
+
return `<span class="prov-chip">${escapeHtml(text)}</span>`;
|
|
4780
|
+
}
|
|
4781
|
+
function capLine2(provenance) {
|
|
4782
|
+
if (provenance?.entitlement?.tier !== "free") {
|
|
4783
|
+
return "";
|
|
4784
|
+
}
|
|
4785
|
+
const analyzed = provenance.scale?.analyzedCommits;
|
|
4786
|
+
if (analyzed === void 0) {
|
|
4787
|
+
return "";
|
|
4788
|
+
}
|
|
4789
|
+
const total = provenance.scale?.totalCommits;
|
|
4790
|
+
const detail = total === void 0 ? `${formatCount2(analyzed)} commits analyzed` : `${formatCount2(analyzed)} of ${formatCount2(total)} commits analyzed`;
|
|
4791
|
+
const label = `Free \xB7 ${detail}`;
|
|
4792
|
+
return `<p class="cap-line">${escapeHtml(label)}</p>`;
|
|
4793
|
+
}
|
|
4164
4794
|
function confidenceBand2(confidence) {
|
|
4165
4795
|
const level = escapeHtml(confidence.level);
|
|
4166
4796
|
const escalation = confidence.escalation === void 0 ? "" : `<p class="confidence-escalation" role="alert">\u26A0 ${escapeHtml(confidence.escalation)}</p>`;
|
|
@@ -4173,7 +4803,7 @@ function substrateBanner(framing) {
|
|
|
4173
4803
|
return framing === "degraded" ? `<p class="banner banner-degraded" role="alert">${escapeHtml(HTML_DEGRADED_BANNER)}</p>` : `<p class="banner banner-metrics-only">${escapeHtml(HTML_METRICS_ONLY_NOTE)}</p>`;
|
|
4174
4804
|
}
|
|
4175
4805
|
function presentGroups(analysis) {
|
|
4176
|
-
return
|
|
4806
|
+
return GROUPS2.filter((group) => analysis.metrics.some((metric) => metric.group === group.id));
|
|
4177
4807
|
}
|
|
4178
4808
|
function toc(narrated, analysis) {
|
|
4179
4809
|
const narrativeLinks = narrated ? [
|
|
@@ -4193,7 +4823,7 @@ ${groupLinks}
|
|
|
4193
4823
|
function summaryBand(summary) {
|
|
4194
4824
|
const findings = summary.keyFindings.map((finding) => `<li>${escapeHtml(finding)}</li>`).join("\n");
|
|
4195
4825
|
return `<section id="summary" class="band" aria-labelledby="summary-h">
|
|
4196
|
-
<h2 id="summary-h">Summary</h2>
|
|
4826
|
+
<h2 id="summary-h"><span class="kicker">TL;DR</span> Summary</h2>
|
|
4197
4827
|
<p class="headline">${escapeHtml(summary.headline)}</p>
|
|
4198
4828
|
<p>${escapeHtml(summary.overview)}</p>
|
|
4199
4829
|
${findings === "" ? "" : `<ul class="key-findings">
|
|
@@ -4204,7 +4834,7 @@ ${findings}
|
|
|
4204
4834
|
function explanationBand(explanation) {
|
|
4205
4835
|
const paragraphs = explanation.paragraphs.map((p) => `<p>${escapeHtml(p)}</p>`).join("\n");
|
|
4206
4836
|
return `<section id="explanation" class="band" aria-labelledby="explanation-h">
|
|
4207
|
-
<h2 id="explanation-h">Explanation</h2>
|
|
4837
|
+
<h2 id="explanation-h"><span class="kicker">What the metrics show</span> Explanation</h2>
|
|
4208
4838
|
${paragraphs}
|
|
4209
4839
|
</section>`;
|
|
4210
4840
|
}
|
|
@@ -4219,7 +4849,7 @@ ${steps}
|
|
|
4219
4849
|
</article>`;
|
|
4220
4850
|
}).join("\n");
|
|
4221
4851
|
return `<section id="coaching" class="band" aria-labelledby="coaching-h">
|
|
4222
|
-
<h2 id="coaching-h">Coaching</h2>
|
|
4852
|
+
<h2 id="coaching-h"><span class="kicker">Improvement plan</span> Coaching</h2>
|
|
4223
4853
|
<p class="coaching-intro">${escapeHtml(coaching.introduction)}</p>
|
|
4224
4854
|
${chapters}
|
|
4225
4855
|
<p class="coaching-closing">${escapeHtml(coaching.closingSummary)}</p>
|
|
@@ -4228,28 +4858,32 @@ ${chapters}
|
|
|
4228
4858
|
function metricGroups(analysis, explanations) {
|
|
4229
4859
|
const sections = presentGroups(analysis).map((group) => {
|
|
4230
4860
|
const metrics = analysis.metrics.filter((metric) => metric.group === group.id);
|
|
4231
|
-
const cards = metrics.map((metric) =>
|
|
4861
|
+
const cards = metrics.map((metric) => metricCard2(metric, explanations)).join("\n");
|
|
4232
4862
|
return `<section id="group-${group.id.toLowerCase()}" class="metric-group" aria-labelledby="group-${group.id.toLowerCase()}-h">
|
|
4233
|
-
<h2 id="group-${group.id.toLowerCase()}-h"
|
|
4863
|
+
<h2 id="group-${group.id.toLowerCase()}-h"><span class="kicker">Group ${escapeHtml(group.id)}</span> ${escapeHtml(group.title)}</h2>
|
|
4234
4864
|
${groupOverviewPanel(group.id, metrics)}
|
|
4865
|
+
<div class="cards">
|
|
4235
4866
|
${cards}
|
|
4867
|
+
</div>
|
|
4236
4868
|
</section>`;
|
|
4237
4869
|
});
|
|
4238
4870
|
return `<main id="main" class="metric-groups">
|
|
4239
4871
|
${sections.join("\n")}
|
|
4240
4872
|
</main>`;
|
|
4241
4873
|
}
|
|
4242
|
-
function
|
|
4874
|
+
function metricCard2(metric, explanations) {
|
|
4243
4875
|
const band = classifyHealth(metric);
|
|
4244
4876
|
const bandHtml = `<span class="health health-${band}"><span class="health-glyph" aria-hidden="true">${HEALTH_GLYPH[band]}</span> ${escapeHtml(HEALTH_LABEL[band])}</span>`;
|
|
4245
|
-
const
|
|
4877
|
+
const stat = metricStat(metric);
|
|
4878
|
+
const statHtml = stat === "" ? "" : `<span class="metric-stat">${escapeHtml(stat)}</span>`;
|
|
4246
4879
|
const explanation = explanations?.[metric.id];
|
|
4880
|
+
const facets = explanation === void 0 ? "" : fourFacets(explanation);
|
|
4881
|
+
const reason = metric.status === "computed" ? "" : `<p class="why">${escapeHtml(metric.reason ?? "Not available.")}</p>`;
|
|
4247
4882
|
return `<details class="metric-card" data-status="${escapeHtml(metric.status)}" data-health="${band}" open>
|
|
4248
|
-
<summary><h3 class="metric-title">${escapeHtml(metric.title)}</h3> ${bandHtml}</summary>
|
|
4883
|
+
<summary><h3 class="metric-title">${escapeHtml(metric.title)}</h3> ${bandHtml}${statHtml}</summary>
|
|
4249
4884
|
<div class="metric-body">
|
|
4250
|
-
${
|
|
4251
|
-
${
|
|
4252
|
-
${explanation === void 0 ? "" : fourFacets(explanation)}
|
|
4885
|
+
${reason}
|
|
4886
|
+
${facets}
|
|
4253
4887
|
</div>
|
|
4254
4888
|
</details>`;
|
|
4255
4889
|
}
|
|
@@ -4273,94 +4907,247 @@ ${list(explanation.needsImprovement)}
|
|
|
4273
4907
|
${list(explanation.suggestions)}
|
|
4274
4908
|
</div>`;
|
|
4275
4909
|
}
|
|
4276
|
-
function
|
|
4277
|
-
if (
|
|
4910
|
+
function metricStat(metric) {
|
|
4911
|
+
if (metric.status !== "computed") {
|
|
4278
4912
|
return "";
|
|
4279
4913
|
}
|
|
4914
|
+
const value = metric.value;
|
|
4915
|
+
if (typeof value === "number") {
|
|
4916
|
+
return Number.isFinite(value) ? fmtStat(value) : "";
|
|
4917
|
+
}
|
|
4280
4918
|
if (typeof value === "string") {
|
|
4281
4919
|
return value;
|
|
4282
4920
|
}
|
|
4283
|
-
const
|
|
4284
|
-
|
|
4921
|
+
const range = rangeField(value);
|
|
4922
|
+
if (range !== void 0) {
|
|
4923
|
+
return `${fmtStat(range.value)}${range.max === 100 ? "%" : ""}`;
|
|
4924
|
+
}
|
|
4925
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
4926
|
+
const nums = Object.entries(value).filter((e) => typeof e[1] === "number" && Number.isFinite(e[1]));
|
|
4927
|
+
for (const key of ["total", "count", "score", "busFactor", "value"]) {
|
|
4928
|
+
const hit = nums.find(([k]) => k === key);
|
|
4929
|
+
if (hit !== void 0) {
|
|
4930
|
+
return fmtStat(hit[1]);
|
|
4931
|
+
}
|
|
4932
|
+
}
|
|
4933
|
+
if (nums.length === 1) {
|
|
4934
|
+
return fmtStat(nums[0][1]);
|
|
4935
|
+
}
|
|
4936
|
+
}
|
|
4937
|
+
return "";
|
|
4285
4938
|
}
|
|
4286
|
-
function
|
|
4939
|
+
function fmtStat(n) {
|
|
4940
|
+
return Number.isInteger(n) ? String(n) : String(Math.round(n * 100) / 100);
|
|
4941
|
+
}
|
|
4942
|
+
function footer(provenance) {
|
|
4943
|
+
const version = provenance?.run?.toolVersion;
|
|
4944
|
+
const parts = [version === void 0 ? "Generated by commit-whisper" : `Generated by commit-whisper v${escapeHtml(version)}`, "schemaVersion 1.0.0"];
|
|
4945
|
+
const ai = provenance?.ai;
|
|
4946
|
+
if (ai !== void 0) {
|
|
4947
|
+
parts.push(`${escapeHtml(ai.provider)}/${escapeHtml(ai.model)}`);
|
|
4948
|
+
}
|
|
4949
|
+
const generatedAt = provenance?.run?.generatedAt;
|
|
4950
|
+
if (generatedAt !== void 0) {
|
|
4951
|
+
parts.push(escapeHtml(generatedAt));
|
|
4952
|
+
}
|
|
4287
4953
|
return `<footer class="footer">
|
|
4288
|
-
<p
|
|
4954
|
+
<p>${parts.join(" \xB7 ")}</p>
|
|
4289
4955
|
</footer>`;
|
|
4290
4956
|
}
|
|
4957
|
+
function formatCount2(n) {
|
|
4958
|
+
if (!Number.isFinite(n)) {
|
|
4959
|
+
return "0";
|
|
4960
|
+
}
|
|
4961
|
+
const negative = n < 0;
|
|
4962
|
+
const digits = Math.abs(Math.trunc(n)).toString();
|
|
4963
|
+
let grouped = "";
|
|
4964
|
+
for (let i = 0; i < digits.length; i++) {
|
|
4965
|
+
if (i > 0 && (digits.length - i) % 3 === 0) {
|
|
4966
|
+
grouped += ",";
|
|
4967
|
+
}
|
|
4968
|
+
grouped += digits[i];
|
|
4969
|
+
}
|
|
4970
|
+
return negative ? `-${grouped}` : grouped;
|
|
4971
|
+
}
|
|
4972
|
+
function isoDate2(iso) {
|
|
4973
|
+
return iso.slice(0, 10);
|
|
4974
|
+
}
|
|
4291
4975
|
var STYLE = `
|
|
4292
4976
|
:root {
|
|
4293
4977
|
color-scheme: dark light;
|
|
4294
|
-
--bg: #
|
|
4295
|
-
--
|
|
4296
|
-
--
|
|
4978
|
+
--bg: #0a0e14; --surface: #11161f; --surface-2: #161c28;
|
|
4979
|
+
--border: #232b3a; --border-soft: #1c2430;
|
|
4980
|
+
--fg: #e8eef6; --fg-soft: #cdd7e4; --muted: #93a1b5; --faint: #5d6b80;
|
|
4981
|
+
--accent: #58a6ff; --accent-2: #7c5cff;
|
|
4982
|
+
--ok: #3fb950; --watch: #e3b341; --risk: #ff6b6b;
|
|
4983
|
+
--shadow: 0 14px 40px -20px rgba(0,0,0,0.7);
|
|
4297
4984
|
}
|
|
4298
4985
|
@media (prefers-color-scheme: light) {
|
|
4299
4986
|
:root {
|
|
4300
|
-
--bg: #ffffff; --surface: #f6f8fa; --
|
|
4301
|
-
--
|
|
4302
|
-
--
|
|
4987
|
+
--bg: #ffffff; --surface: #f6f8fa; --surface-2: #eef1f5;
|
|
4988
|
+
--border: #d0d7de; --border-soft: #e4e8ec;
|
|
4989
|
+
--fg: #1f2328; --fg-soft: #2c333d; --muted: #57606a; --faint: #8b949e;
|
|
4990
|
+
--accent: #0969da; --accent-2: #8250df;
|
|
4991
|
+
--ok: #1a7f37; --watch: #9a6700; --risk: #cf222e;
|
|
4992
|
+
--shadow: 0 14px 40px -22px rgba(140,150,170,0.5);
|
|
4303
4993
|
}
|
|
4304
4994
|
}
|
|
4305
4995
|
* { box-sizing: border-box; }
|
|
4306
4996
|
body {
|
|
4307
|
-
margin: 0; padding: 0
|
|
4308
|
-
background:
|
|
4309
|
-
|
|
4997
|
+
margin: 0; padding: 0 1.25rem 4rem;
|
|
4998
|
+
background:
|
|
4999
|
+
radial-gradient(1100px 520px at 85% -8%, rgba(124,92,255,0.13), transparent 60%),
|
|
5000
|
+
radial-gradient(900px 460px at -5% 2%, rgba(88,166,255,0.11), transparent 55%),
|
|
5001
|
+
var(--bg);
|
|
5002
|
+
color: var(--fg);
|
|
5003
|
+
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
4310
5004
|
line-height: 1.6;
|
|
5005
|
+
-webkit-font-smoothing: antialiased;
|
|
4311
5006
|
}
|
|
4312
|
-
main, header, nav, section, footer { max-width:
|
|
4313
|
-
h1 { font-size: 2rem; margin: 1.5rem 0 0.25rem; }
|
|
4314
|
-
h2 { font-size: 1.
|
|
5007
|
+
main, header, nav, section, footer { max-width: 66rem; margin-inline: auto; }
|
|
5008
|
+
h1 { font-size: 2rem; margin: 1.5rem 0 0.25rem; letter-spacing: -0.02em; }
|
|
5009
|
+
h2 { font-size: 1.5rem; margin: 2.25rem 0 1rem; letter-spacing: -0.01em; }
|
|
4315
5010
|
h3 { font-size: 1.1rem; margin: 1.25rem 0 0.5rem; }
|
|
4316
|
-
h4 { font-size: 0.
|
|
4317
|
-
a { color: var(--accent); }
|
|
4318
|
-
a:
|
|
5011
|
+
h4 { font-size: 0.8rem; margin: 0.75rem 0 0.25rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); }
|
|
5012
|
+
a { color: var(--accent); text-decoration: none; }
|
|
5013
|
+
a:hover { text-decoration: underline; }
|
|
5014
|
+
a:focus-visible, :focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }
|
|
4319
5015
|
.skip-link {
|
|
4320
5016
|
position: absolute; left: -9999px; top: 0;
|
|
4321
|
-
background: var(--surface); color: var(--fg); padding: 0.5rem 1rem; z-index:
|
|
5017
|
+
background: var(--surface); color: var(--fg); padding: 0.5rem 1rem; z-index: 50; border-radius: 0 0 8px 0;
|
|
4322
5018
|
}
|
|
4323
5019
|
.skip-link:focus { left: 0; }
|
|
4324
|
-
.
|
|
4325
|
-
.
|
|
4326
|
-
.
|
|
4327
|
-
|
|
4328
|
-
|
|
5020
|
+
.band > h2, .metric-group > h2 { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
|
|
5021
|
+
.kicker { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); background: rgba(88,166,255,0.12); padding: 0.22rem 0.55rem; border-radius: 6px; }
|
|
5022
|
+
.masthead {
|
|
5023
|
+
position: relative; margin-top: 2.5rem; padding: 2.4rem 2.5rem; overflow: hidden;
|
|
5024
|
+
border: 1px solid var(--border); border-radius: 22px;
|
|
5025
|
+
background: linear-gradient(135deg, rgba(88,166,255,0.10), rgba(124,92,255,0.06)), var(--surface);
|
|
5026
|
+
box-shadow: var(--shadow);
|
|
5027
|
+
}
|
|
5028
|
+
.masthead::before {
|
|
5029
|
+
content: ""; position: absolute; inset: 0; pointer-events: none;
|
|
5030
|
+
background: radial-gradient(600px 200px at 90% -40%, rgba(124,92,255,0.22), transparent 70%);
|
|
5031
|
+
}
|
|
5032
|
+
.masthead h1 { margin: 0; font-size: 1.95rem; position: relative; display: flex; align-items: center; gap: 0.75rem; }
|
|
5033
|
+
.masthead h1::before {
|
|
5034
|
+
content: "\\25D1"; display: inline-grid; place-items: center;
|
|
5035
|
+
width: 2.7rem; height: 2.7rem; font-size: 1.45rem; color: #fff;
|
|
5036
|
+
background: linear-gradient(135deg, var(--accent), var(--accent-2));
|
|
5037
|
+
border-radius: 0.72rem; box-shadow: 0 10px 26px -8px rgba(124,92,255,0.75);
|
|
5038
|
+
}
|
|
5039
|
+
.masthead .tagline { color: var(--muted); margin: 0.4rem 0 0; position: relative; max-width: 46rem; }
|
|
5040
|
+
.prov-chips { position: relative; margin: 0.85rem 0 0; display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; color: var(--fg-soft); font-size: 0.92rem; }
|
|
5041
|
+
.prov-chip { white-space: nowrap; }
|
|
5042
|
+
.prov-sep { color: var(--faint); }
|
|
5043
|
+
.cap-line { position: relative; margin: 0.7rem 0 0; color: var(--muted); font-size: 0.9rem; }
|
|
5044
|
+
.confidence {
|
|
5045
|
+
position: relative; margin: 1.5rem 0 0; padding: 0.85rem 1.1rem;
|
|
5046
|
+
border: 1px solid rgba(63,185,80,0.4); border-left: 4px solid var(--ok); border-radius: 12px;
|
|
5047
|
+
background: linear-gradient(90deg, rgba(63,185,80,0.12), transparent);
|
|
5048
|
+
}
|
|
5049
|
+
.confidence-high { border-color: rgba(63,185,80,0.4); border-left-color: var(--ok); }
|
|
5050
|
+
.confidence-medium { border-color: rgba(227,179,65,0.4); border-left-color: var(--watch); background: linear-gradient(90deg, rgba(227,179,65,0.12), transparent); }
|
|
5051
|
+
.confidence-low { border-color: rgba(255,107,107,0.4); border-left-color: var(--risk); background: linear-gradient(90deg, rgba(255,107,107,0.12), transparent); }
|
|
5052
|
+
.confidence p { margin: 0; }
|
|
5053
|
+
.confidence-label, .confidence strong { text-transform: uppercase; letter-spacing: 0.04em; font-weight: 700; }
|
|
5054
|
+
.confidence-high .confidence-label, .confidence-high strong { color: var(--ok); }
|
|
5055
|
+
.confidence-medium .confidence-label, .confidence-medium strong { color: var(--watch); }
|
|
5056
|
+
.confidence-low .confidence-label, .confidence-low strong { color: var(--risk); }
|
|
4329
5057
|
.confidence-escalation { color: var(--risk); font-weight: 600; }
|
|
4330
|
-
.banner { border-radius:
|
|
4331
|
-
.banner-degraded { border: 1px solid
|
|
4332
|
-
.banner-metrics-only { border: 1px solid var(--border); color: var(--muted); }
|
|
4333
|
-
.toc {
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
:
|
|
4337
|
-
|
|
4338
|
-
.
|
|
4339
|
-
.
|
|
5058
|
+
.banner { border-radius: 12px; padding: 0.85rem 1.1rem; margin: 1.25rem 0; }
|
|
5059
|
+
.banner-degraded { border: 1px solid rgba(255,107,107,0.4); color: var(--risk); font-weight: 600; background: linear-gradient(90deg, rgba(255,107,107,0.12), transparent); }
|
|
5060
|
+
.banner-metrics-only { border: 1px solid var(--border); color: var(--muted); background: var(--surface); }
|
|
5061
|
+
.toc {
|
|
5062
|
+
position: sticky; top: 0; z-index: 20; margin: 1.5rem auto 0; padding: 0.6rem 0;
|
|
5063
|
+
background: color-mix(in srgb, var(--bg) 78%, transparent); backdrop-filter: blur(12px);
|
|
5064
|
+
border-bottom: 1px solid var(--border-soft);
|
|
5065
|
+
}
|
|
5066
|
+
.toc h2 { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--faint); margin: 0 0 0.45rem; }
|
|
5067
|
+
.toc h2::before { content: none; }
|
|
5068
|
+
.toc ul { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 0.4rem; }
|
|
5069
|
+
.toc a { display: inline-block; padding: 0.32rem 0.8rem; border-radius: 999px; font-size: 0.85rem; color: var(--muted); border: 1px solid transparent; }
|
|
5070
|
+
.toc a:hover { color: var(--fg); background: var(--surface-2); border-color: var(--border); text-decoration: none; }
|
|
5071
|
+
.band, .metric-group { scroll-margin-top: 4rem; }
|
|
5072
|
+
.band { margin: 2.5rem auto; }
|
|
5073
|
+
:target { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 8px; }
|
|
5074
|
+
.headline { font-size: 1.3rem; font-weight: 700; letter-spacing: -0.01em; }
|
|
5075
|
+
.lead, .explanation p, .coaching-intro, .coaching-closing { color: var(--fg-soft); }
|
|
5076
|
+
.key-findings { list-style: none; padding: 0; margin: 1.2rem 0 0; display: grid; gap: 0.6rem; }
|
|
5077
|
+
.key-findings li { position: relative; padding: 0.8rem 1rem 0.8rem 2.5rem; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; }
|
|
5078
|
+
.key-findings li::before { content: "\\203A"; position: absolute; left: 1rem; top: 0.7rem; color: var(--accent); font-weight: 800; font-size: 1.1rem; }
|
|
5079
|
+
.chapter { background: var(--surface); border: 1px solid var(--border); border-left: 4px solid var(--accent-2); border-radius: 14px; padding: 1.1rem 1.35rem; margin: 1rem 0; }
|
|
5080
|
+
.chapter h3 { margin: 0 0 0.6rem; }
|
|
5081
|
+
.chapter ol { margin: 0; padding-left: 1.2rem; display: grid; gap: 0.5rem; color: var(--fg-soft); }
|
|
5082
|
+
.coaching-closing { margin-top: 1rem; padding: 1rem 1.2rem; border: 1px solid rgba(124,92,255,0.35); border-radius: 12px; background: linear-gradient(90deg, rgba(124,92,255,0.10), transparent); }
|
|
5083
|
+
.metric-group .chart-panel + .metric-card { margin-top: 1.2rem; }
|
|
5084
|
+
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 1rem; margin-top: 1.2rem; align-items: stretch; }
|
|
5085
|
+
.cards > .metric-card { margin: 0; }
|
|
5086
|
+
.metric-card { background: var(--surface); border: 1px solid var(--border); border-radius: 14px; padding: 0.7rem 1.1rem; margin: 0.85rem 0; transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease; }
|
|
5087
|
+
.metric-card:hover { transform: translateY(-2px); border-color: #2f3a4d; box-shadow: var(--shadow); }
|
|
5088
|
+
.metric-card > summary { cursor: pointer; list-style-position: inside; display: flex; align-items: center; gap: 0.55rem; flex-wrap: wrap; }
|
|
4340
5089
|
.metric-card[data-health="risk"] { border-left: 4px solid var(--risk); }
|
|
4341
5090
|
.metric-card[data-health="watch"] { border-left: 4px solid var(--watch); }
|
|
4342
|
-
.metric-card[data-
|
|
5091
|
+
.metric-card[data-health="ok"] { border-left: 4px solid var(--ok); }
|
|
5092
|
+
.metric-card[data-status="not_available"] { opacity: 0.72; border-left: 4px solid var(--faint); }
|
|
4343
5093
|
.metric-title { display: inline; font-size: 1.05rem; margin: 0; font-weight: 600; }
|
|
5094
|
+
.metric-stat { margin-left: auto; font-size: 1.5rem; font-weight: 700; letter-spacing: -0.01em; color: var(--fg); }
|
|
5095
|
+
.why { color: var(--muted); margin: 0.4rem 0 0; }
|
|
4344
5096
|
.metric-body { margin-top: 0.5rem; }
|
|
4345
5097
|
.metric-status { color: var(--muted); font-size: 0.85rem; margin: 0.25rem 0; }
|
|
5098
|
+
.metric-value code { background: var(--surface-2); border: 1px solid var(--border-soft); border-radius: 6px; padding: 0.15rem 0.45rem; }
|
|
4346
5099
|
.metric-card code { word-break: break-word; }
|
|
5100
|
+
.facets { margin-top: 0.6rem; }
|
|
5101
|
+
.facet-meaning { color: var(--fg-soft); }
|
|
4347
5102
|
.facets ul { margin: 0.25rem 0 0.5rem; }
|
|
4348
|
-
.health { font-size: 0.
|
|
4349
|
-
.health-glyph { font-size:
|
|
4350
|
-
.health-ok { color: var(--ok); }
|
|
4351
|
-
.health-watch { color: var(--watch); }
|
|
4352
|
-
.health-risk { color: var(--risk); }
|
|
4353
|
-
.health-na { color: var(--
|
|
4354
|
-
.chart-panel { margin: 1rem 0; background: var(--surface); border: 1px solid var(--border); border-radius:
|
|
4355
|
-
.chart-panel figcaption { color: var(--muted); font-size: 0.9rem; margin-bottom: 0.
|
|
5103
|
+
.health { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.78rem; font-weight: 700; padding: 0.18rem 0.55rem; border-radius: 999px; white-space: nowrap; }
|
|
5104
|
+
.health-glyph { font-size: 0.95rem; }
|
|
5105
|
+
.health-ok { color: var(--ok); background: rgba(63,185,80,0.13); }
|
|
5106
|
+
.health-watch { color: var(--watch); background: rgba(227,179,65,0.14); }
|
|
5107
|
+
.health-risk { color: var(--risk); background: rgba(255,107,107,0.14); }
|
|
5108
|
+
.health-na { color: var(--faint); background: rgba(93,107,128,0.14); }
|
|
5109
|
+
.chart-panel { margin: 1rem 0; background: linear-gradient(180deg, color-mix(in srgb, var(--surface) 88%, var(--accent) 4%), var(--surface)); border: 1px solid var(--border); border-radius: 10px; padding: 1rem 1.25rem; box-shadow: 0 10px 30px -18px rgba(0,0,0,0.5); }
|
|
5110
|
+
.chart-panel figcaption { color: var(--muted); font-size: 0.9rem; margin-bottom: 0.75rem; }
|
|
4356
5111
|
.chart-source { font-style: italic; }
|
|
4357
5112
|
.chart-empty { color: var(--muted); }
|
|
4358
|
-
.chart-svg { width: 100%; height:
|
|
4359
|
-
.chart-svg.chart-sparkline { height:
|
|
5113
|
+
.chart-svg { width: 100%; height: auto; color: var(--accent); display: block; }
|
|
5114
|
+
.chart-svg.chart-sparkline { height: 2.25rem; width: 8rem; }
|
|
5115
|
+
.chart-svg.chart-gauge { height: 0.9rem; width: 12rem; max-width: 60%; }
|
|
5116
|
+
.chart-svg.chart-radar { max-width: 30rem; margin-inline: auto; }
|
|
5117
|
+
.metric-visual .chart-svg { max-width: 38rem; }
|
|
5118
|
+
.chart-svg text { font-family: inherit; }
|
|
5119
|
+
.chart-svg .chart-tick, .chart-svg .chart-label { fill: var(--muted); font-size: 11px; }
|
|
5120
|
+
.chart-svg .radar-label { fill: var(--muted); font-size: 10px; }
|
|
5121
|
+
.chart-svg .chart-grid { stroke: var(--border); stroke-width: 1; opacity: 0.55; }
|
|
5122
|
+
.chart-svg .chart-axis { stroke: var(--border); stroke-width: 1; }
|
|
5123
|
+
.chart-svg .chart-dot { fill: var(--accent); stroke: var(--surface); stroke-width: 1; }
|
|
5124
|
+
.chart-svg .grad-area-top { stop-color: var(--accent); stop-opacity: 0.38; }
|
|
5125
|
+
.chart-svg .grad-area-bottom { stop-color: var(--accent); stop-opacity: 0; }
|
|
5126
|
+
.chart-svg .grad-fill-1 { stop-color: var(--accent); }
|
|
5127
|
+
.chart-svg .grad-fill-2 { stop-color: var(--accent-2); }
|
|
4360
5128
|
.chart-svg .bar { fill: var(--accent); }
|
|
4361
5129
|
.chart-svg .gauge-track { fill: var(--border); }
|
|
4362
5130
|
.chart-svg .gauge-fill { fill: var(--accent); }
|
|
4363
|
-
.chart-svg .radar-
|
|
5131
|
+
.chart-svg .radar-grid { fill: none; stroke: var(--border); stroke-width: 0.5; opacity: 0.7; }
|
|
5132
|
+
.chart-svg .radar-axis { stroke: var(--border); stroke-width: 0.4; opacity: 0.7; }
|
|
5133
|
+
.chart-svg .radar-area { fill: var(--accent); fill-opacity: 0.45; stroke: var(--accent); stroke-width: 1; stroke-linejoin: round; }
|
|
5134
|
+
.chart-svg .radar-dot { fill: var(--accent); stroke: var(--surface); stroke-width: 0.6; }
|
|
5135
|
+
.chart-svg.chart-radialgauge { max-width: 12rem; margin-inline: auto; }
|
|
5136
|
+
.chart-svg.chart-donut { max-width: 30rem; }
|
|
5137
|
+
.chart-svg .gauge-ring-track { stroke: var(--border); }
|
|
5138
|
+
.chart-svg .gauge-value { fill: var(--fg); font-weight: 700; font-size: 40px; }
|
|
5139
|
+
.chart-svg .donut-label { fill: var(--fg-soft); font-size: 13px; }
|
|
5140
|
+
.chart-svg .slice-0 { fill: #58a6ff; stroke: #58a6ff; }
|
|
5141
|
+
.chart-svg .slice-1 { fill: #7c5cff; stroke: #7c5cff; }
|
|
5142
|
+
.chart-svg .slice-2 { fill: #3fb950; stroke: #3fb950; }
|
|
5143
|
+
.chart-svg .slice-3 { fill: #e3b341; stroke: #e3b341; }
|
|
5144
|
+
.chart-svg .slice-4 { fill: #2dd4bf; stroke: #2dd4bf; }
|
|
5145
|
+
.chart-svg .slice-5 { fill: #f472b6; stroke: #f472b6; }
|
|
5146
|
+
.chart-svg .donut-seg { stroke: var(--surface); stroke-width: 1.5; }
|
|
5147
|
+
.chart-cells { display: grid; gap: 1.2rem; margin-top: 0.25rem; }
|
|
5148
|
+
.chart-sub { min-width: 0; }
|
|
5149
|
+
.chart-sub h4 { margin: 0 0 0.4rem; font-size: 0.9rem; color: var(--fg); text-transform: none; letter-spacing: 0; }
|
|
5150
|
+
@media (min-width: 720px) { .chart-cells.two { grid-template-columns: 1.5fr 1fr; align-items: center; } }
|
|
4364
5151
|
.metric-visual { margin: 0.5rem 0; }
|
|
4365
5152
|
.metric-visual-range { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
|
|
4366
5153
|
.metric-number { font-size: 1.4rem; font-weight: 700; }
|
|
@@ -4369,13 +5156,12 @@ a:focus-visible, :focus-visible { outline: 2px solid var(--accent); outline-offs
|
|
|
4369
5156
|
.data-table table { border-collapse: collapse; width: 100%; font-size: 0.85rem; margin-top: 0.5rem; }
|
|
4370
5157
|
.data-table th, .data-table td { border: 1px solid var(--border); padding: 0.25rem 0.5rem; text-align: left; }
|
|
4371
5158
|
.data-table caption { text-align: left; color: var(--muted); padding-bottom: 0.25rem; }
|
|
4372
|
-
.footer { color: var(--
|
|
5159
|
+
.footer { color: var(--faint); border-top: 1px solid var(--border-soft); margin-top: 3rem; padding-top: 1.2rem; font-size: 0.85rem; display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
|
|
4373
5160
|
@media (prefers-reduced-motion: reduce) {
|
|
4374
5161
|
* { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; }
|
|
4375
5162
|
}
|
|
4376
5163
|
`;
|
|
4377
5164
|
var DISCLOSURE_SCRIPT = `
|
|
4378
|
-
document.querySelectorAll('details.metric-card[data-health="ok"]').forEach(function(d){d.open=false;});
|
|
4379
5165
|
document.querySelectorAll('details.data-table').forEach(function(d){d.open=false;});
|
|
4380
5166
|
`;
|
|
4381
5167
|
|
|
@@ -4414,7 +5200,7 @@ function safe2(n) {
|
|
|
4414
5200
|
function round2(n) {
|
|
4415
5201
|
return Math.round(safe2(n) * 100) / 100;
|
|
4416
5202
|
}
|
|
4417
|
-
function
|
|
5203
|
+
function extent(values) {
|
|
4418
5204
|
let min = Number.POSITIVE_INFINITY;
|
|
4419
5205
|
let max = Number.NEGATIVE_INFINITY;
|
|
4420
5206
|
for (const raw of values) {
|
|
@@ -4430,7 +5216,7 @@ function sparkline(series) {
|
|
|
4430
5216
|
return "";
|
|
4431
5217
|
}
|
|
4432
5218
|
const values = series.map((p) => safe2(p.value));
|
|
4433
|
-
const [min, max] =
|
|
5219
|
+
const [min, max] = extent(values);
|
|
4434
5220
|
const span = max - min;
|
|
4435
5221
|
const midGlyph = SPARK_GLYPHS[Math.floor(SPARK_GLYPHS.length / 2)];
|
|
4436
5222
|
if (span === 0) {
|
|
@@ -4447,7 +5233,7 @@ function textBars(series) {
|
|
|
4447
5233
|
if (series.length === 0) {
|
|
4448
5234
|
return "";
|
|
4449
5235
|
}
|
|
4450
|
-
const [, max] =
|
|
5236
|
+
const [, max] = extent(series.map((p) => p.value));
|
|
4451
5237
|
const top = max <= 0 ? 1 : max;
|
|
4452
5238
|
const labels = series.map((p) => escapeCell(p.label));
|
|
4453
5239
|
const labelWidth = labels.reduce((w, label) => Math.max(w, label.length), 0);
|
|
@@ -4479,7 +5265,7 @@ function mermaidXychart(series, title2) {
|
|
|
4479
5265
|
"```"
|
|
4480
5266
|
].join("\n");
|
|
4481
5267
|
}
|
|
4482
|
-
function
|
|
5268
|
+
function representativeSeries(metrics) {
|
|
4483
5269
|
for (const metric of metrics) {
|
|
4484
5270
|
if (metric.status !== "computed") {
|
|
4485
5271
|
continue;
|
|
@@ -4496,7 +5282,7 @@ function representativeSeries2(metrics) {
|
|
|
4496
5282
|
return void 0;
|
|
4497
5283
|
}
|
|
4498
5284
|
function groupOverview(group, metrics) {
|
|
4499
|
-
const rep =
|
|
5285
|
+
const rep = representativeSeries(metrics);
|
|
4500
5286
|
if (rep === void 0) {
|
|
4501
5287
|
return GROUP_OVERVIEW_NONE;
|
|
4502
5288
|
}
|
|
@@ -4540,7 +5326,7 @@ function metricVisualMarkdown(metric) {
|
|
|
4540
5326
|
}
|
|
4541
5327
|
|
|
4542
5328
|
// src/render/markdown/markdown-renderer.ts
|
|
4543
|
-
var
|
|
5329
|
+
var GROUPS3 = [
|
|
4544
5330
|
{ id: "A", title: "Activity & Cadence", description: "How the project moves over time." },
|
|
4545
5331
|
{ id: "B", title: "Contribution & Ownership", description: "How the work is distributed across the team." },
|
|
4546
5332
|
{ id: "C", title: "Commit Message Quality", description: "How clearly the history communicates intent." },
|
|
@@ -4552,42 +5338,100 @@ var MD_DEGRADED_BANNER = "> \u26A0 **Narrative unavailable \u2014 showing raw an
|
|
|
4552
5338
|
var MD_METRICS_ONLY_NOTE = "_Narrative skipped (--no-ai) \u2014 run interactively or add a key for the full report._";
|
|
4553
5339
|
function renderMarkdown(report) {
|
|
4554
5340
|
const route = classifyReport(report);
|
|
4555
|
-
const
|
|
5341
|
+
const provenance = report.provenance;
|
|
5342
|
+
const body = route.kind === "showpiece" ? renderShowpiece3(route.report, provenance) : renderSubstrate3(route.analysis, route.framing, provenance);
|
|
4556
5343
|
return `${body}
|
|
4557
5344
|
`;
|
|
4558
5345
|
}
|
|
4559
5346
|
function blocks(...parts) {
|
|
4560
5347
|
return parts.filter((part) => part !== "").join("\n\n");
|
|
4561
5348
|
}
|
|
4562
|
-
function renderShowpiece3(report) {
|
|
5349
|
+
function renderShowpiece3(report, provenance) {
|
|
4563
5350
|
const { summary, explanation, coaching, explanations, confidence } = report.narrative;
|
|
4564
5351
|
return blocks(
|
|
4565
|
-
|
|
5352
|
+
masthead3(provenance),
|
|
4566
5353
|
confidence === void 0 ? "" : confidenceBlock(confidence),
|
|
4567
5354
|
summaryBand2(summary),
|
|
4568
5355
|
explanationBand2(explanation),
|
|
4569
5356
|
coachingBand2(coaching),
|
|
4570
|
-
|
|
4571
|
-
footer2("showpiece")
|
|
5357
|
+
metricsSection2(report.analysis, explanations),
|
|
5358
|
+
footer2("showpiece", provenance)
|
|
4572
5359
|
);
|
|
4573
5360
|
}
|
|
4574
|
-
function renderSubstrate3(analysis, framing) {
|
|
5361
|
+
function renderSubstrate3(analysis, framing, provenance) {
|
|
4575
5362
|
if (framing === "degraded") {
|
|
4576
5363
|
return blocks(
|
|
4577
5364
|
MD_DEGRADED_BANNER,
|
|
4578
|
-
|
|
5365
|
+
masthead3(provenance),
|
|
4579
5366
|
"**Confidence:** \u2014 _(no narrative to assess)_",
|
|
4580
5367
|
stubBand("Summary", "Narrative unavailable \u2014 showing raw analysis."),
|
|
4581
5368
|
stubBand("Explanation", "Narrative unavailable."),
|
|
4582
5369
|
stubBand("Coaching", "Narrative unavailable."),
|
|
4583
|
-
|
|
4584
|
-
footer2("degraded")
|
|
5370
|
+
metricsSection2(analysis, void 0),
|
|
5371
|
+
footer2("degraded", provenance)
|
|
4585
5372
|
);
|
|
4586
5373
|
}
|
|
4587
|
-
return blocks(
|
|
5374
|
+
return blocks(masthead3(provenance), metricsSection2(analysis, void 0), footer2("metrics-only", provenance));
|
|
5375
|
+
}
|
|
5376
|
+
function masthead3(provenance) {
|
|
5377
|
+
return blocks(title(provenance), provenanceChips3(provenance), capLine3(provenance));
|
|
5378
|
+
}
|
|
5379
|
+
function title(provenance) {
|
|
5380
|
+
const name = provenance?.repo?.name;
|
|
5381
|
+
return name === void 0 ? "# commit-whisper" : `# commit-whisper \u2014 ${escapeCell(name)}`;
|
|
5382
|
+
}
|
|
5383
|
+
function provenanceChips3(provenance) {
|
|
5384
|
+
const repo = provenance?.repo;
|
|
5385
|
+
const scale = provenance?.scale;
|
|
5386
|
+
const chips = [];
|
|
5387
|
+
if (repo?.name !== void 0) {
|
|
5388
|
+
chips.push(escapeCell(repo.name));
|
|
5389
|
+
}
|
|
5390
|
+
if (repo?.branch !== void 0) {
|
|
5391
|
+
chips.push(escapeCell(repo.branch));
|
|
5392
|
+
}
|
|
5393
|
+
const commits = scale?.totalCommits ?? scale?.analyzedCommits;
|
|
5394
|
+
if (commits !== void 0) {
|
|
5395
|
+
chips.push(`${formatCount3(commits)} ${commits === 1 ? "commit" : "commits"}`);
|
|
5396
|
+
}
|
|
5397
|
+
if (scale?.contributors !== void 0) {
|
|
5398
|
+
chips.push(`${formatCount3(scale.contributors)} ${scale.contributors === 1 ? "contributor" : "contributors"}`);
|
|
5399
|
+
}
|
|
5400
|
+
const generatedAt = provenance?.run?.generatedAt;
|
|
5401
|
+
if (generatedAt !== void 0) {
|
|
5402
|
+
chips.push(`analyzed ${isoDate3(generatedAt)}`);
|
|
5403
|
+
}
|
|
5404
|
+
return chips.length === 0 ? "" : `_${chips.join(" \xB7 ")}_`;
|
|
5405
|
+
}
|
|
5406
|
+
function capLine3(provenance) {
|
|
5407
|
+
if (provenance?.entitlement?.tier !== "free") {
|
|
5408
|
+
return "";
|
|
5409
|
+
}
|
|
5410
|
+
const analyzed = provenance.scale?.analyzedCommits;
|
|
5411
|
+
if (analyzed === void 0) {
|
|
5412
|
+
return "";
|
|
5413
|
+
}
|
|
5414
|
+
const total = provenance.scale?.totalCommits;
|
|
5415
|
+
const detail = total === void 0 ? `${formatCount3(analyzed)} commits analyzed` : `${formatCount3(analyzed)} of ${formatCount3(total)} commits analyzed`;
|
|
5416
|
+
return `Free \xB7 ${detail}`;
|
|
5417
|
+
}
|
|
5418
|
+
function formatCount3(n) {
|
|
5419
|
+
if (!Number.isFinite(n)) {
|
|
5420
|
+
return "0";
|
|
5421
|
+
}
|
|
5422
|
+
const negative = n < 0;
|
|
5423
|
+
const digits = Math.abs(Math.trunc(n)).toString();
|
|
5424
|
+
let grouped = "";
|
|
5425
|
+
for (let i = 0; i < digits.length; i++) {
|
|
5426
|
+
if (i > 0 && (digits.length - i) % 3 === 0) {
|
|
5427
|
+
grouped += ",";
|
|
5428
|
+
}
|
|
5429
|
+
grouped += digits[i];
|
|
5430
|
+
}
|
|
5431
|
+
return negative ? `-${grouped}` : grouped;
|
|
4588
5432
|
}
|
|
4589
|
-
function
|
|
4590
|
-
return
|
|
5433
|
+
function isoDate3(iso) {
|
|
5434
|
+
return iso.slice(0, 10);
|
|
4591
5435
|
}
|
|
4592
5436
|
function confidenceBlock(confidence) {
|
|
4593
5437
|
const head = `**Confidence:** ${confidence.level} \u2014 ${inlineProse(confidence.rationale)}`;
|
|
@@ -4634,14 +5478,14 @@ function stubBand(name, note) {
|
|
|
4634
5478
|
|
|
4635
5479
|
_${note}_`;
|
|
4636
5480
|
}
|
|
4637
|
-
function
|
|
4638
|
-
const present =
|
|
5481
|
+
function metricsSection2(analysis, explanations) {
|
|
5482
|
+
const present = GROUPS3.filter((group) => analysis.metrics.some((metric) => metric.group === group.id));
|
|
4639
5483
|
if (present.length === 0) {
|
|
4640
5484
|
return "## Metrics\n\n_No metrics computed._";
|
|
4641
5485
|
}
|
|
4642
5486
|
const sections = present.map((group) => {
|
|
4643
5487
|
const metrics = analysis.metrics.filter((metric) => metric.group === group.id);
|
|
4644
|
-
const cards = metrics.map((metric) =>
|
|
5488
|
+
const cards = metrics.map((metric) => metricCard3(metric, explanations)).join("\n\n");
|
|
4645
5489
|
const overview = groupOverview(group.id, metrics);
|
|
4646
5490
|
return `### ${group.id} \xB7 ${escapeCell(group.title)}
|
|
4647
5491
|
|
|
@@ -4655,42 +5499,42 @@ ${cards}`;
|
|
|
4655
5499
|
|
|
4656
5500
|
${sections.join("\n\n")}`;
|
|
4657
5501
|
}
|
|
4658
|
-
function
|
|
5502
|
+
function metricCard3(metric, explanations) {
|
|
4659
5503
|
const band = classifyHealth(metric);
|
|
4660
5504
|
const visual = metricVisualMarkdown(metric);
|
|
4661
5505
|
const suffix = visual.headingSuffix === "" ? "" : ` ${visual.headingSuffix}`;
|
|
4662
|
-
const
|
|
5506
|
+
const heading = `#### ${escapeCell(metric.title)} ${HEALTH_GLYPH[band]} ${HEALTH_LABEL[band]}${suffix}`;
|
|
4663
5507
|
const body = visual.body === "" ? "" : `
|
|
4664
5508
|
|
|
4665
5509
|
${visual.body}`;
|
|
4666
|
-
return `${
|
|
5510
|
+
return `${heading}${body}
|
|
4667
5511
|
|
|
4668
5512
|
${metricBullets(metric, explanations)}`;
|
|
4669
5513
|
}
|
|
4670
5514
|
function metricBullets(metric, explanations) {
|
|
4671
|
-
const value =
|
|
5515
|
+
const value = valueBullet2(metric);
|
|
4672
5516
|
const explanation = explanations?.[metric.id];
|
|
4673
5517
|
if (explanation === void 0) {
|
|
4674
5518
|
return value;
|
|
4675
5519
|
}
|
|
4676
|
-
return [value, ...
|
|
5520
|
+
return [value, ...facetBullets2(explanation)].join("\n");
|
|
4677
5521
|
}
|
|
4678
|
-
function
|
|
5522
|
+
function valueBullet2(metric) {
|
|
4679
5523
|
if (metric.status !== "computed") {
|
|
4680
5524
|
const reason = metric.reason === void 0 ? "" : ` \u2014 ${escapeCell(metric.reason)}`;
|
|
4681
5525
|
return `- **Value** \u2014 _not available${reason}_`;
|
|
4682
5526
|
}
|
|
4683
5527
|
return `- **Value** \u2014 ${escapeCell(formatValue3(metric.value))}`;
|
|
4684
5528
|
}
|
|
4685
|
-
function
|
|
5529
|
+
function facetBullets2(explanation) {
|
|
4686
5530
|
return [
|
|
4687
5531
|
`- **What it means** \u2014 ${inlineProse(explanation.explanation)}`,
|
|
4688
|
-
...
|
|
4689
|
-
...
|
|
4690
|
-
...
|
|
5532
|
+
...arrayFacet2("Strengths", explanation.goodBehaviours),
|
|
5533
|
+
...arrayFacet2("Needs improvement", explanation.needsImprovement),
|
|
5534
|
+
...arrayFacet2("Suggestions", explanation.suggestions)
|
|
4691
5535
|
];
|
|
4692
5536
|
}
|
|
4693
|
-
function
|
|
5537
|
+
function arrayFacet2(label, items) {
|
|
4694
5538
|
if (items.length === 0) {
|
|
4695
5539
|
return [`- **${label}** \u2014 \u2014`];
|
|
4696
5540
|
}
|
|
@@ -4708,8 +5552,22 @@ function formatValue3(value) {
|
|
|
4708
5552
|
}
|
|
4709
5553
|
return JSON.stringify(value) ?? "";
|
|
4710
5554
|
}
|
|
4711
|
-
function footer2(kind) {
|
|
4712
|
-
const
|
|
5555
|
+
function footer2(kind, provenance) {
|
|
5556
|
+
const version = provenance?.run?.toolVersion;
|
|
5557
|
+
const parts = [
|
|
5558
|
+
version === void 0 ? "Generated by commit-whisper" : `Generated by commit-whisper v${escapeCell(version)}`,
|
|
5559
|
+
"schemaVersion 1.0.0"
|
|
5560
|
+
];
|
|
5561
|
+
const ai = provenance?.ai;
|
|
5562
|
+
if (ai !== void 0) {
|
|
5563
|
+
parts.push(`${escapeCell(ai.provider)}/${escapeCell(ai.model)}`);
|
|
5564
|
+
}
|
|
5565
|
+
const generatedAt = provenance?.run?.generatedAt;
|
|
5566
|
+
if (generatedAt !== void 0) {
|
|
5567
|
+
parts.push(escapeCell(generatedAt));
|
|
5568
|
+
}
|
|
5569
|
+
const base = `---
|
|
5570
|
+
${parts.join(" \xB7 ")}`;
|
|
4713
5571
|
return kind === "metrics-only" ? `${base}
|
|
4714
5572
|
|
|
4715
5573
|
${MD_METRICS_ONLY_NOTE}` : base;
|
|
@@ -4810,10 +5668,17 @@ function resolveNumstatPath(raw) {
|
|
|
4810
5668
|
if (!raw.includes(" => ")) {
|
|
4811
5669
|
return raw;
|
|
4812
5670
|
}
|
|
4813
|
-
const
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
5671
|
+
const open2 = raw.indexOf("{");
|
|
5672
|
+
const close = open2 === -1 ? -1 : raw.indexOf("}", open2 + 1);
|
|
5673
|
+
if (open2 !== -1 && close !== -1) {
|
|
5674
|
+
const inside = raw.slice(open2 + 1, close);
|
|
5675
|
+
const arrow = inside.indexOf(" => ");
|
|
5676
|
+
if (arrow !== -1) {
|
|
5677
|
+
const prefix = raw.slice(0, open2);
|
|
5678
|
+
const next = inside.slice(arrow + " => ".length);
|
|
5679
|
+
const suffix = raw.slice(close + 1);
|
|
5680
|
+
return `${prefix}${next}${suffix}`.replace(/\/{2,}/g, "/");
|
|
5681
|
+
}
|
|
4817
5682
|
}
|
|
4818
5683
|
return raw.slice(raw.indexOf(" => ") + " => ".length);
|
|
4819
5684
|
}
|
|
@@ -5065,6 +5930,88 @@ function createRetrieve(deps = {}) {
|
|
|
5065
5930
|
return async (config) => (isRemoteTarget(config.repoTarget) ? remote : local)(config);
|
|
5066
5931
|
}
|
|
5067
5932
|
|
|
5933
|
+
// src/cli/provenance.ts
|
|
5934
|
+
import { basename } from "path";
|
|
5935
|
+
function buildProvenance(input) {
|
|
5936
|
+
const source = isRemoteTarget(input.target) ? "remote" : "local";
|
|
5937
|
+
const repo = {
|
|
5938
|
+
name: source === "remote" ? remoteSlug(input.target) : localName(input.target),
|
|
5939
|
+
target: source === "remote" ? stripCredentials(input.target) : input.target,
|
|
5940
|
+
source
|
|
5941
|
+
};
|
|
5942
|
+
const branch = branchLabel(input.branch);
|
|
5943
|
+
if (branch !== void 0) {
|
|
5944
|
+
repo.branch = branch;
|
|
5945
|
+
}
|
|
5946
|
+
const scale = {
|
|
5947
|
+
totalCommits: input.totalCommits,
|
|
5948
|
+
analyzedCommits: input.analyzedCommits
|
|
5949
|
+
};
|
|
5950
|
+
if (input.contributors !== void 0) {
|
|
5951
|
+
scale.contributors = input.contributors;
|
|
5952
|
+
}
|
|
5953
|
+
const provenance = {
|
|
5954
|
+
repo,
|
|
5955
|
+
scale,
|
|
5956
|
+
run: { generatedAt: input.generatedAt, toolVersion: input.toolVersion },
|
|
5957
|
+
entitlement: buildEntitlement(input.tier, input.commitCap)
|
|
5958
|
+
};
|
|
5959
|
+
if (input.provider !== void 0 && input.model !== void 0) {
|
|
5960
|
+
provenance.ai = { provider: input.provider, model: input.model };
|
|
5961
|
+
}
|
|
5962
|
+
return provenance;
|
|
5963
|
+
}
|
|
5964
|
+
function buildEntitlement(tier, commitCap) {
|
|
5965
|
+
const entitlement = { tier };
|
|
5966
|
+
if (tier === "free" && commitCap !== void 0) {
|
|
5967
|
+
entitlement.commitCap = commitCap;
|
|
5968
|
+
}
|
|
5969
|
+
return entitlement;
|
|
5970
|
+
}
|
|
5971
|
+
function branchLabel(branch) {
|
|
5972
|
+
switch (branch.kind) {
|
|
5973
|
+
case "named":
|
|
5974
|
+
return branch.name;
|
|
5975
|
+
case "all":
|
|
5976
|
+
return "all branches";
|
|
5977
|
+
case "head":
|
|
5978
|
+
return void 0;
|
|
5979
|
+
// the default sentinel carries no meaningful label
|
|
5980
|
+
default:
|
|
5981
|
+
return void 0;
|
|
5982
|
+
}
|
|
5983
|
+
}
|
|
5984
|
+
function stripCredentials(target) {
|
|
5985
|
+
return target.replace(/^(https?:\/\/)[^@/]*@/i, "$1");
|
|
5986
|
+
}
|
|
5987
|
+
function remoteSlug(target) {
|
|
5988
|
+
try {
|
|
5989
|
+
const url = new URL(target.trim());
|
|
5990
|
+
const path = stripTrailingSlashes(url.pathname).replace(/\.git$/i, "");
|
|
5991
|
+
const segments = path.split("/").filter((segment) => segment !== "");
|
|
5992
|
+
if (segments.length >= 2) {
|
|
5993
|
+
return `${segments.at(-2)}/${segments.at(-1)}`;
|
|
5994
|
+
}
|
|
5995
|
+
if (segments.length === 1) {
|
|
5996
|
+
return segments[0];
|
|
5997
|
+
}
|
|
5998
|
+
return url.host;
|
|
5999
|
+
} catch {
|
|
6000
|
+
return stripCredentials(target.trim());
|
|
6001
|
+
}
|
|
6002
|
+
}
|
|
6003
|
+
function localName(target) {
|
|
6004
|
+
const trimmed = stripTrailingSlashes(target.trim());
|
|
6005
|
+
const base = basename(trimmed);
|
|
6006
|
+
if (base === "" || base === "." || base === "..") {
|
|
6007
|
+
return trimmed === "" ? target.trim() : trimmed;
|
|
6008
|
+
}
|
|
6009
|
+
return base;
|
|
6010
|
+
}
|
|
6011
|
+
|
|
6012
|
+
// src/cli/version.ts
|
|
6013
|
+
var VERSION = "1.1.0";
|
|
6014
|
+
|
|
5068
6015
|
// src/cli/write-file.ts
|
|
5069
6016
|
import { writeFile as fsWriteFile } from "fs/promises";
|
|
5070
6017
|
var defaultWriteFile = async (path, content) => {
|
|
@@ -5077,6 +6024,7 @@ async function runPipeline(config, deps = {}) {
|
|
|
5077
6024
|
const narrate = deps.narrate ?? createNarrate();
|
|
5078
6025
|
const preflight = deps.preflight ?? preflightProvider;
|
|
5079
6026
|
const ui2 = deps.ui ?? ui;
|
|
6027
|
+
const progress = deps.progress ?? noopProgress;
|
|
5080
6028
|
const writeStdout2 = deps.writeStdout ?? ((text) => {
|
|
5081
6029
|
process.stdout.write(text);
|
|
5082
6030
|
});
|
|
@@ -5094,7 +6042,8 @@ async function runPipeline(config, deps = {}) {
|
|
|
5094
6042
|
if (config.aiMode === "off" && config.provenance.aiMode === "default") {
|
|
5095
6043
|
ui2.info("Running metrics-only \u2014 for the AI narrative, run interactively or set a provider key.");
|
|
5096
6044
|
}
|
|
5097
|
-
const history = await retrieve(config);
|
|
6045
|
+
const history = await stage(progress, "Retrieving commit history\u2026", () => retrieve(config));
|
|
6046
|
+
progress.done(`Retrieved ${history.commits.length} commit(s) from ${history.repoTarget}`);
|
|
5098
6047
|
ui2.debug?.(`Retrieved ${history.commits.length} commit(s) from ${history.repoTarget}.`);
|
|
5099
6048
|
const selection = selectCommitsWithNotice(history, projectSelection(config));
|
|
5100
6049
|
if (selection.truncation !== void 0) {
|
|
@@ -5107,17 +6056,60 @@ async function runPipeline(config, deps = {}) {
|
|
|
5107
6056
|
mailmap: emptyMailmap()
|
|
5108
6057
|
// real .mailmap ingestion is deferred
|
|
5109
6058
|
};
|
|
5110
|
-
const analysis = analyze(selection.history, ctx);
|
|
6059
|
+
const analysis = await stage(progress, "Computing metrics\u2026", () => analyze(selection.history, ctx));
|
|
6060
|
+
progress.done(`Computed metrics over ${selection.history.commits.length} commit(s)`);
|
|
5111
6061
|
ui2.debug?.(`Analyzed ${selection.history.commits.length} commit(s); aiMode=${config.aiMode}.`);
|
|
5112
|
-
const outcome = await
|
|
5113
|
-
|
|
6062
|
+
const outcome = await narrateStage(
|
|
6063
|
+
progress,
|
|
6064
|
+
config,
|
|
6065
|
+
() => narrateOutcome(config, narrateConfig, analysis, narrate, preflightReason)
|
|
6066
|
+
);
|
|
6067
|
+
const provenance = buildProvenance({
|
|
6068
|
+
target: config.repoTarget,
|
|
6069
|
+
branch: config.branch,
|
|
6070
|
+
totalCommits: history.commits.length,
|
|
6071
|
+
analyzedCommits: selection.history.commits.length,
|
|
6072
|
+
contributors: countContributors(selection.history.commits, ctx.mailmap),
|
|
6073
|
+
provider: config.provider,
|
|
6074
|
+
model: config.llmModel,
|
|
6075
|
+
generatedAt: config.analysisTimestamp,
|
|
6076
|
+
toolVersion: VERSION,
|
|
6077
|
+
tier: config.entitlement.tier,
|
|
6078
|
+
commitCap: config.entitlement.commitCap
|
|
6079
|
+
});
|
|
6080
|
+
const report = reportFromOutcome(analysis, outcome, provenance);
|
|
5114
6081
|
const targets = planOutputs(config.outputFormats, config.outputPath);
|
|
6082
|
+
progress.start("Rendering report\u2026");
|
|
6083
|
+
progress.done("Report ready");
|
|
5115
6084
|
const htmlFilePath = await emitOutputs(report, targets, { writeStdout: writeStdout2, writeFile: writeFile3, ui: ui2 });
|
|
5116
6085
|
if (autoOpen && htmlFilePath !== void 0) {
|
|
5117
6086
|
await tryOpen(openBrowser, htmlFilePath, ui2);
|
|
5118
6087
|
}
|
|
5119
6088
|
return report.degraded ? ExitCode.Degraded : ExitCode.Success;
|
|
5120
6089
|
}
|
|
6090
|
+
async function stage(progress, label, fn) {
|
|
6091
|
+
progress.start(label);
|
|
6092
|
+
try {
|
|
6093
|
+
return await fn();
|
|
6094
|
+
} catch (err) {
|
|
6095
|
+
progress.fail();
|
|
6096
|
+
throw err;
|
|
6097
|
+
}
|
|
6098
|
+
}
|
|
6099
|
+
async function narrateStage(progress, config, run) {
|
|
6100
|
+
if (config.aiMode === "off") {
|
|
6101
|
+
return run();
|
|
6102
|
+
}
|
|
6103
|
+
progress.start("Generating AI narrative\u2026");
|
|
6104
|
+
try {
|
|
6105
|
+
const outcome = await run();
|
|
6106
|
+
progress.done(outcome.kind === "narrated" ? "AI narrative ready" : "Narrative unavailable \u2014 metrics-only");
|
|
6107
|
+
return outcome;
|
|
6108
|
+
} catch (err) {
|
|
6109
|
+
progress.fail("AI narrative failed");
|
|
6110
|
+
throw err;
|
|
6111
|
+
}
|
|
6112
|
+
}
|
|
5121
6113
|
async function emitOutputs(report, targets, io) {
|
|
5122
6114
|
let htmlFilePath;
|
|
5123
6115
|
for (const target of targets) {
|
|
@@ -5186,6 +6178,14 @@ async function narrateOutcome(config, narrateConfig, analysis, narrate, prefligh
|
|
|
5186
6178
|
}
|
|
5187
6179
|
return narrate(analysis, narrateConfig);
|
|
5188
6180
|
}
|
|
6181
|
+
function countContributors(commits, mailmap) {
|
|
6182
|
+
const keys = /* @__PURE__ */ new Set();
|
|
6183
|
+
for (const commit of commits) {
|
|
6184
|
+
const identity = canonicalizeIdentity(commit.author, mailmap);
|
|
6185
|
+
keys.add(`${identity.email}\0${identity.name}`);
|
|
6186
|
+
}
|
|
6187
|
+
return keys.size;
|
|
6188
|
+
}
|
|
5189
6189
|
|
|
5190
6190
|
// src/cli/show-config.ts
|
|
5191
6191
|
var UNSET = "(unset)";
|
|
@@ -5241,9 +6241,6 @@ function formatShowConfig(config, secrets) {
|
|
|
5241
6241
|
return lines.join("\n");
|
|
5242
6242
|
}
|
|
5243
6243
|
|
|
5244
|
-
// src/cli/version.ts
|
|
5245
|
-
var VERSION = "1.0.7";
|
|
5246
|
-
|
|
5247
6244
|
// src/cli/cli.ts
|
|
5248
6245
|
var PROVIDERS3 = ["ollama", "openai", "gemini", "anthropic", "openai-compatible"];
|
|
5249
6246
|
var OUTPUT_FORMATS3 = ["terminal", "html", "markdown", "json"];
|
|
@@ -5292,7 +6289,7 @@ async function main(argv, deps = {}) {
|
|
|
5292
6289
|
});
|
|
5293
6290
|
try {
|
|
5294
6291
|
if (argv.length === 0) {
|
|
5295
|
-
return await runZeroArg({ deps, ui: ui2, env, cwd, stdinIsTTY, stdoutIsTTY });
|
|
6292
|
+
return await runZeroArg({ deps, ui: ui2, env, cwd, stdinIsTTY, stdoutIsTTY, stderrIsTTY });
|
|
5296
6293
|
}
|
|
5297
6294
|
const program = buildProgram();
|
|
5298
6295
|
try {
|
|
@@ -5328,10 +6325,10 @@ async function main(argv, deps = {}) {
|
|
|
5328
6325
|
return ExitCode.Success;
|
|
5329
6326
|
}
|
|
5330
6327
|
const entitlement = entitlementForHeadlessRun(resolution);
|
|
5331
|
-
const
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
6328
|
+
const runLevel = resolveLogLevel({ verbose: opts.verbose, quiet: opts.quiet, env });
|
|
6329
|
+
const runColor = resolveColor({ env, isTTY: Boolean(stderrIsTTY) });
|
|
6330
|
+
const runUi = deps.ui ?? createUi(process.stderr, { level: runLevel, color: runColor });
|
|
6331
|
+
const progress = makeProgress(deps, stderrIsTTY, runLevel, runColor);
|
|
5335
6332
|
const config = resolveRunConfig({
|
|
5336
6333
|
cwd,
|
|
5337
6334
|
env,
|
|
@@ -5354,7 +6351,8 @@ async function main(argv, deps = {}) {
|
|
|
5354
6351
|
openAllowed: opts.open !== false,
|
|
5355
6352
|
// honoured only when interactive (false here)
|
|
5356
6353
|
deps,
|
|
5357
|
-
ui: runUi
|
|
6354
|
+
ui: runUi,
|
|
6355
|
+
progress
|
|
5358
6356
|
});
|
|
5359
6357
|
} catch (err) {
|
|
5360
6358
|
ui2.error(messageForError(err));
|
|
@@ -5391,7 +6389,8 @@ async function resolveAndRun(input) {
|
|
|
5391
6389
|
nonInteractive: input.nonInteractive,
|
|
5392
6390
|
openAllowed: input.openAllowed,
|
|
5393
6391
|
deps: input.deps,
|
|
5394
|
-
ui: input.ui
|
|
6392
|
+
ui: input.ui,
|
|
6393
|
+
progress: input.progress
|
|
5395
6394
|
});
|
|
5396
6395
|
}
|
|
5397
6396
|
async function runResolved(input) {
|
|
@@ -5409,11 +6408,21 @@ async function runResolved(input) {
|
|
|
5409
6408
|
aiKey,
|
|
5410
6409
|
gitToken,
|
|
5411
6410
|
ui: input.ui,
|
|
6411
|
+
progress: input.progress,
|
|
5412
6412
|
writeStdout: input.deps.writeStdout,
|
|
5413
6413
|
autoOpen,
|
|
5414
6414
|
...input.deps.runDeps
|
|
5415
6415
|
});
|
|
5416
6416
|
}
|
|
6417
|
+
function makeProgress(deps, stderrIsTTY, level, color) {
|
|
6418
|
+
if (deps.progress !== void 0) {
|
|
6419
|
+
return deps.progress;
|
|
6420
|
+
}
|
|
6421
|
+
if (stderrIsTTY !== true) {
|
|
6422
|
+
return noopProgress;
|
|
6423
|
+
}
|
|
6424
|
+
return createProgress(process.stderr, { tty: true, level, color });
|
|
6425
|
+
}
|
|
5417
6426
|
async function runZeroArg(ctx) {
|
|
5418
6427
|
const { interactive } = detectCapability({
|
|
5419
6428
|
nonInteractive: false,
|
|
@@ -5451,6 +6460,7 @@ async function runZeroArg(ctx) {
|
|
|
5451
6460
|
};
|
|
5452
6461
|
const runAnalysis = async (flags) => {
|
|
5453
6462
|
try {
|
|
6463
|
+
const liveConfigFile = ctx.deps.configFile ?? await readSettings(ctx.env);
|
|
5454
6464
|
return await resolveAndRun({
|
|
5455
6465
|
flags,
|
|
5456
6466
|
env: ctx.env,
|
|
@@ -5460,24 +6470,67 @@ async function runZeroArg(ctx) {
|
|
|
5460
6470
|
analysisTimestamp: ctx.deps.analysisTimestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
5461
6471
|
nonInteractive: false,
|
|
5462
6472
|
openAllowed: true,
|
|
5463
|
-
configFile,
|
|
6473
|
+
configFile: liveConfigFile,
|
|
5464
6474
|
entitlement,
|
|
5465
6475
|
deps: ctx.deps,
|
|
5466
|
-
ui: ctx.ui
|
|
6476
|
+
ui: ctx.ui,
|
|
6477
|
+
progress: makeProgress(
|
|
6478
|
+
ctx.deps,
|
|
6479
|
+
ctx.stderrIsTTY,
|
|
6480
|
+
resolveLogLevel({ env: ctx.env }),
|
|
6481
|
+
resolveColor({ env: ctx.env, isTTY: Boolean(ctx.stderrIsTTY) })
|
|
6482
|
+
)
|
|
5467
6483
|
});
|
|
5468
6484
|
} catch (err) {
|
|
5469
6485
|
ctx.ui.error(messageForError(err));
|
|
5470
6486
|
return exitCodeForError(err);
|
|
5471
6487
|
}
|
|
5472
6488
|
};
|
|
6489
|
+
const resolveLiveAi = async () => {
|
|
6490
|
+
const liveConfigFile = ctx.deps.configFile ?? await readSettings(ctx.env);
|
|
6491
|
+
const liveEnv = readEnvLayer(ctx.env);
|
|
6492
|
+
return {
|
|
6493
|
+
configFile: liveConfigFile,
|
|
6494
|
+
envLayer: liveEnv,
|
|
6495
|
+
provider: liveEnv.provider ?? liveConfigFile.provider,
|
|
6496
|
+
llmModel: liveEnv.llmModel ?? liveConfigFile.llmModel,
|
|
6497
|
+
llmBaseUrl: liveEnv.llmBaseUrl ?? liveConfigFile.llmBaseUrl
|
|
6498
|
+
};
|
|
6499
|
+
};
|
|
6500
|
+
const buildDoctorConfig = (envLayerNow, configFileNow) => ({
|
|
6501
|
+
branch: envLayerNow.branch,
|
|
6502
|
+
authorFilter: envLayerNow.authorFilter,
|
|
6503
|
+
startDate: envLayerNow.startDate,
|
|
6504
|
+
endDate: envLayerNow.endDate,
|
|
6505
|
+
timezone: envLayerNow.timezone ?? configFileNow.timezone,
|
|
6506
|
+
noMerges: envLayerNow.noMerges,
|
|
6507
|
+
outputFormats: envLayerNow.outputFormats ?? configFileNow.outputFormats,
|
|
6508
|
+
outputPath: envLayerNow.outputPath,
|
|
6509
|
+
maxCommits: envLayerNow.maxCommits ?? configFileNow.maxCommits,
|
|
6510
|
+
aiMode: envLayerNow.aiMode,
|
|
6511
|
+
llmBaseUrl: envLayerNow.llmBaseUrl ?? configFileNow.llmBaseUrl,
|
|
6512
|
+
logLevel: resolveLogLevel({ env: ctx.env }),
|
|
6513
|
+
color: resolveColor({ env: ctx.env, isTTY: Boolean(ctx.stdoutIsTTY) })
|
|
6514
|
+
});
|
|
5473
6515
|
const envDiagnostics = readEnvDiagnostics(ctx.env, aiLayer.provider);
|
|
6516
|
+
const doctorConfig = buildDoctorConfig(envLayer, configFile);
|
|
6517
|
+
const refreshDoctor = async () => {
|
|
6518
|
+
const live = await resolveLiveAi();
|
|
6519
|
+
return {
|
|
6520
|
+
provider: live.provider,
|
|
6521
|
+
llmModel: live.llmModel,
|
|
6522
|
+
envDiagnostics: readEnvDiagnostics(ctx.env, live.provider),
|
|
6523
|
+
doctorConfig: buildDoctorConfig(live.envLayer, live.configFile)
|
|
6524
|
+
};
|
|
6525
|
+
};
|
|
5474
6526
|
const probeReachability = async () => {
|
|
6527
|
+
const live = await resolveLiveAi();
|
|
5475
6528
|
const narrateConfig = {
|
|
5476
6529
|
aiMode: "auto",
|
|
5477
|
-
provider:
|
|
5478
|
-
llmModel:
|
|
5479
|
-
llmBaseUrl:
|
|
5480
|
-
aiKey: readAiKey(ctx.env,
|
|
6530
|
+
provider: live.provider,
|
|
6531
|
+
llmModel: live.llmModel,
|
|
6532
|
+
llmBaseUrl: live.llmBaseUrl,
|
|
6533
|
+
aiKey: readAiKey(ctx.env, live.provider)
|
|
5481
6534
|
};
|
|
5482
6535
|
const result = await (ctx.deps.preflight ?? preflightProvider)(narrateConfig, {});
|
|
5483
6536
|
return result.reachable ? { kind: "reachable" } : { kind: "unreachable", reason: result.reason };
|
|
@@ -5490,8 +6543,21 @@ async function runZeroArg(ctx) {
|
|
|
5490
6543
|
gitTokenConfigured: readGitToken(ctx.env) !== void 0,
|
|
5491
6544
|
envDiagnostics,
|
|
5492
6545
|
probeReachability,
|
|
6546
|
+
doctorConfig,
|
|
6547
|
+
refreshDoctor,
|
|
5493
6548
|
loadSettings: () => readSettings(ctx.env),
|
|
5494
6549
|
saveSettings: (data) => writeSettings(ctx.env, data),
|
|
6550
|
+
// Re-resolve the live AI provider/model after a Settings save (config < env,
|
|
6551
|
+
// mirroring the resolver) so a mid-session change cures the no-AI state and
|
|
6552
|
+
// refreshes the header without restarting the launchpad.
|
|
6553
|
+
reloadAiState: async () => {
|
|
6554
|
+
const liveConfigFile = ctx.deps.configFile ?? await readSettings(ctx.env);
|
|
6555
|
+
const liveEnv = readEnvLayer(ctx.env);
|
|
6556
|
+
return {
|
|
6557
|
+
provider: liveEnv.provider ?? liveConfigFile.provider,
|
|
6558
|
+
llmModel: liveEnv.llmModel ?? liveConfigFile.llmModel
|
|
6559
|
+
};
|
|
6560
|
+
},
|
|
5495
6561
|
// License actions (Story 7.2): the only in-app key entry + the browser hand-offs.
|
|
5496
6562
|
activateLicense: (key) => (ctx.deps.activateLicense ?? defaultActivateLicense)(ctx.env, key),
|
|
5497
6563
|
deactivateLicense: () => (ctx.deps.deactivateLicense ?? defaultDeactivateLicense)(ctx.env),
|