commit-whisper 1.0.8 → 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 +1472 -428
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -145,18 +145,35 @@ 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;
|
|
@@ -660,11 +677,18 @@ function tierForVariantName(variantName) {
|
|
|
660
677
|
}
|
|
661
678
|
return "single-device";
|
|
662
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
|
+
}
|
|
663
687
|
function tierForValidation(v) {
|
|
664
688
|
if (!v.valid) {
|
|
665
689
|
return "free";
|
|
666
690
|
}
|
|
667
|
-
return
|
|
691
|
+
return tierForLicense({ variantName: v.variantName, activationLimit: v.activationLimit });
|
|
668
692
|
}
|
|
669
693
|
function entitlementForTier(tier) {
|
|
670
694
|
if (tier === "free") {
|
|
@@ -714,7 +738,7 @@ async function activateLicense(deps) {
|
|
|
714
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).`
|
|
715
739
|
};
|
|
716
740
|
}
|
|
717
|
-
return { ok: true, tier:
|
|
741
|
+
return { ok: true, tier: tierForLicense({ variantName: result.variantName, activationLimit: result.activationLimit }) };
|
|
718
742
|
}
|
|
719
743
|
async function deactivateLicense(deps) {
|
|
720
744
|
if (deps.licenseKey === void 0 || deps.licenseKey === "") {
|
|
@@ -807,6 +831,7 @@ function createLemonSqueezyActivator(deps = {}) {
|
|
|
807
831
|
instanceId: json.instance?.id,
|
|
808
832
|
variantName: json.meta?.variant_name,
|
|
809
833
|
variantId: json.meta?.variant_id,
|
|
834
|
+
activationLimit: json.license_key?.activation_limit,
|
|
810
835
|
error: json.error ?? void 0
|
|
811
836
|
};
|
|
812
837
|
};
|
|
@@ -1018,6 +1043,106 @@ function resolveColor(input) {
|
|
|
1018
1043
|
return input.isTTY;
|
|
1019
1044
|
}
|
|
1020
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
|
+
}
|
|
1021
1146
|
|
|
1022
1147
|
// src/cli/exit-codes.ts
|
|
1023
1148
|
var ExitCode = {
|
|
@@ -1044,7 +1169,7 @@ function messageForError(err) {
|
|
|
1044
1169
|
|
|
1045
1170
|
// src/cli/interactive.ts
|
|
1046
1171
|
import { isCancel, multiselect as clackMultiselect, select as clackSelect, text as clackText } from "@clack/prompts";
|
|
1047
|
-
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";
|
|
1048
1173
|
var FLAGS_CHEATSHEET = [
|
|
1049
1174
|
"Common commands:",
|
|
1050
1175
|
" commit-whisper . analyze the current repository",
|
|
@@ -1083,11 +1208,16 @@ var PROVIDER_OPTIONS = [
|
|
|
1083
1208
|
{ value: "openai-compatible", label: "OpenAI-compatible" }
|
|
1084
1209
|
];
|
|
1085
1210
|
var BASE_URL_PROVIDERS = /* @__PURE__ */ new Set(["ollama", "openai-compatible"]);
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
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
|
+
}
|
|
1091
1221
|
function aiSegment(state) {
|
|
1092
1222
|
if (state.provider === void 0) {
|
|
1093
1223
|
return "\u26A0 not configured";
|
|
@@ -1111,8 +1241,8 @@ function buildLaunchpadOptions(state) {
|
|
|
1111
1241
|
{ value: "analyze-cwd", label: "Analyze this repository", hint: "the current directory" },
|
|
1112
1242
|
{ value: "analyze-remote", label: "Analyze a remote repository", hint: "clone a URL" },
|
|
1113
1243
|
{ value: "settings", label: "Settings", hint: "provider, model, default format" },
|
|
1114
|
-
{ value: "status", label: "
|
|
1115
|
-
{ value: "help", label: "Help
|
|
1244
|
+
{ value: "status", label: "Doctor", hint: "diagnose your setup" },
|
|
1245
|
+
{ value: "help", label: "Help", hint: "show the flag reference" }
|
|
1116
1246
|
];
|
|
1117
1247
|
if (state.licensed) {
|
|
1118
1248
|
options.push({ value: "deactivate", label: "Deactivate license", hint: "free this device" });
|
|
@@ -1131,19 +1261,16 @@ var STATUS_LABEL_WIDTH = 12;
|
|
|
1131
1261
|
function statusLabel(text) {
|
|
1132
1262
|
return text.padEnd(STATUS_LABEL_WIDTH);
|
|
1133
1263
|
}
|
|
1134
|
-
function
|
|
1264
|
+
function reachabilityAnnotation(reachability) {
|
|
1135
1265
|
switch (reachability.kind) {
|
|
1136
1266
|
case "reachable":
|
|
1137
|
-
return
|
|
1267
|
+
return "\u2713 reachable";
|
|
1138
1268
|
case "unreachable":
|
|
1139
|
-
return
|
|
1269
|
+
return `\u26A0 unreachable \u2014 ${reachability.reason}`;
|
|
1140
1270
|
default:
|
|
1141
|
-
return
|
|
1271
|
+
return "\u26A0 not configured";
|
|
1142
1272
|
}
|
|
1143
1273
|
}
|
|
1144
|
-
function aiBlock(state, reachability) {
|
|
1145
|
-
return [`${statusLabel("AI")}${aiSegment(state)}`, reachabilityLine(reachability)];
|
|
1146
|
-
}
|
|
1147
1274
|
function environmentBlock(envVars) {
|
|
1148
1275
|
const prefixes = envVars.map((v) => ` ${v.set ? "\u2713" : "\u2717"} ${v.name}`);
|
|
1149
1276
|
const stateColumn = Math.max(0, ...prefixes.map((p) => p.length)) + 2;
|
|
@@ -1157,15 +1284,91 @@ function environmentBlock(envVars) {
|
|
|
1157
1284
|
function repositoryLine(state) {
|
|
1158
1285
|
return state.isRepo ? `${statusLabel("Repository")}\u2713 ${cwdSegment(state)}` : `${statusLabel("Repository")}\u2014 not a git repo`;
|
|
1159
1286
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
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)}`;
|
|
1162
1362
|
const lines = [
|
|
1163
|
-
"
|
|
1363
|
+
"Doctor",
|
|
1164
1364
|
"",
|
|
1165
|
-
|
|
1166
|
-
|
|
1365
|
+
licenseLine,
|
|
1366
|
+
aiLine,
|
|
1367
|
+
repositoryLine(state),
|
|
1167
1368
|
...environmentBlock(envVars),
|
|
1168
|
-
|
|
1369
|
+
...settingsBlock(config),
|
|
1370
|
+
...runScopeBlock(config),
|
|
1371
|
+
...operationalBlock(config)
|
|
1169
1372
|
];
|
|
1170
1373
|
if (reachability.kind === "not-configured") {
|
|
1171
1374
|
lines.push("", NO_AI_FIX);
|
|
@@ -1245,6 +1448,28 @@ function writeLine(output, text) {
|
|
|
1245
1448
|
output.write(text.endsWith("\n") ? text : `${text}
|
|
1246
1449
|
`);
|
|
1247
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
|
+
}
|
|
1248
1473
|
function clackLaunchpadSelect(output) {
|
|
1249
1474
|
return async ({ message, options }) => {
|
|
1250
1475
|
const result = await clackSelect({ message, options, output });
|
|
@@ -1259,6 +1484,7 @@ function clackGuidedPrompts(output) {
|
|
|
1259
1484
|
message: opts.message,
|
|
1260
1485
|
placeholder: opts.placeholder,
|
|
1261
1486
|
defaultValue: opts.defaultValue,
|
|
1487
|
+
initialValue: opts.initialValue,
|
|
1262
1488
|
// `@clack` may pass `undefined` (empty input); our validators are total over strings.
|
|
1263
1489
|
validate: validate === void 0 ? void 0 : (value) => validate(value ?? ""),
|
|
1264
1490
|
output
|
|
@@ -1292,7 +1518,7 @@ function validateRemoteUrl(value) {
|
|
|
1292
1518
|
function errorOf(result) {
|
|
1293
1519
|
return "error" in result ? result.error : void 0;
|
|
1294
1520
|
}
|
|
1295
|
-
async function collectGuidedInputs(prompts) {
|
|
1521
|
+
async function collectGuidedInputs(prompts, initialFormats = ["terminal"]) {
|
|
1296
1522
|
const limitRaw = await prompts.text({
|
|
1297
1523
|
message: "Limit \u2014 most-recent commits to analyze",
|
|
1298
1524
|
placeholder: "all history",
|
|
@@ -1312,7 +1538,7 @@ async function collectGuidedInputs(prompts) {
|
|
|
1312
1538
|
const formats = await prompts.multiselect({
|
|
1313
1539
|
message: "Output \u2014 one or more formats",
|
|
1314
1540
|
options: OUTPUT_FORMAT_OPTIONS,
|
|
1315
|
-
initialValues:
|
|
1541
|
+
initialValues: initialFormats
|
|
1316
1542
|
});
|
|
1317
1543
|
if (formats === null) {
|
|
1318
1544
|
return null;
|
|
@@ -1332,6 +1558,17 @@ async function collectGuidedInputs(prompts) {
|
|
|
1332
1558
|
flags.outputFormats = formats.length > 0 ? formats : ["terminal"];
|
|
1333
1559
|
return flags;
|
|
1334
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
|
+
}
|
|
1335
1572
|
async function runGuidedAnalyze(deps, mode, output) {
|
|
1336
1573
|
if (deps.state.provider === void 0) {
|
|
1337
1574
|
writeLine(output, NO_AI_INTERSTITIAL);
|
|
@@ -1352,7 +1589,7 @@ async function runGuidedAnalyze(deps, mode, output) {
|
|
|
1352
1589
|
);
|
|
1353
1590
|
}
|
|
1354
1591
|
}
|
|
1355
|
-
const inputs = await collectGuidedInputs(prompts);
|
|
1592
|
+
const inputs = await collectGuidedInputs(prompts, await loadDefaultFormats(deps));
|
|
1356
1593
|
if (inputs === null) {
|
|
1357
1594
|
return;
|
|
1358
1595
|
}
|
|
@@ -1363,15 +1600,25 @@ async function runGuidedAnalyze(deps, mode, output) {
|
|
|
1363
1600
|
writeLine(output, `\u25B8 Next time: ${formatEquivalentCommand(target, flags)}`);
|
|
1364
1601
|
}
|
|
1365
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
|
+
}
|
|
1366
1612
|
let reachability = { kind: "not-configured" };
|
|
1367
1613
|
if (deps.state.provider !== void 0 && deps.probeReachability !== void 0) {
|
|
1614
|
+
writeLine(output, `Testing connection to ${deps.state.provider}\u2026`);
|
|
1368
1615
|
try {
|
|
1369
1616
|
reachability = await deps.probeReachability();
|
|
1370
1617
|
} catch (err) {
|
|
1371
1618
|
reachability = { kind: "unreachable", reason: err instanceof Error ? err.message : "probe failed" };
|
|
1372
1619
|
}
|
|
1373
1620
|
}
|
|
1374
|
-
writeLine(output, formatStatusReport(deps.state,
|
|
1621
|
+
writeLine(output, formatStatusReport(deps.state, envDiagnostics, reachability, doctorConfig));
|
|
1375
1622
|
}
|
|
1376
1623
|
async function runSettings(deps, output) {
|
|
1377
1624
|
const prompts = deps.prompts ?? clackGuidedPrompts(output);
|
|
@@ -1391,7 +1638,15 @@ async function runSettings(deps, output) {
|
|
|
1391
1638
|
if (provider === null) {
|
|
1392
1639
|
return;
|
|
1393
1640
|
}
|
|
1394
|
-
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
|
+
});
|
|
1395
1650
|
if (model === null) {
|
|
1396
1651
|
return;
|
|
1397
1652
|
}
|
|
@@ -1399,46 +1654,56 @@ async function runSettings(deps, output) {
|
|
|
1399
1654
|
if (BASE_URL_PROVIDERS.has(provider)) {
|
|
1400
1655
|
baseUrl = await prompts.text({
|
|
1401
1656
|
message: "Base URL",
|
|
1402
|
-
placeholder: "e.g. http://localhost:11434"
|
|
1657
|
+
placeholder: "e.g. http://localhost:11434",
|
|
1658
|
+
initialValue: current.llmBaseUrl
|
|
1403
1659
|
});
|
|
1404
1660
|
if (baseUrl === null) {
|
|
1405
1661
|
return;
|
|
1406
1662
|
}
|
|
1407
1663
|
}
|
|
1408
|
-
const
|
|
1409
|
-
message: "Default output
|
|
1410
|
-
options: OUTPUT_FORMAT_OPTIONS
|
|
1411
|
-
|
|
1664
|
+
const formats = await prompts.multiselect({
|
|
1665
|
+
message: "Default output \u2014 one or more formats",
|
|
1666
|
+
options: OUTPUT_FORMAT_OPTIONS,
|
|
1667
|
+
initialValues: current.outputFormats
|
|
1412
1668
|
});
|
|
1413
|
-
if (
|
|
1414
|
-
return;
|
|
1415
|
-
}
|
|
1416
|
-
const timezone = await prompts.text({ message: "Timezone (optional)", placeholder: "e.g. UTC / Europe/Athens" });
|
|
1417
|
-
if (timezone === null) {
|
|
1669
|
+
if (formats === null) {
|
|
1418
1670
|
return;
|
|
1419
1671
|
}
|
|
1420
|
-
const
|
|
1421
|
-
message: "
|
|
1422
|
-
placeholder: "
|
|
1423
|
-
|
|
1672
|
+
const timezone = await prompts.text({
|
|
1673
|
+
message: "Timezone (optional)",
|
|
1674
|
+
placeholder: "e.g. UTC / Europe/Athens",
|
|
1675
|
+
initialValue: current.timezone
|
|
1424
1676
|
});
|
|
1425
|
-
if (
|
|
1677
|
+
if (timezone === null) {
|
|
1426
1678
|
return;
|
|
1427
1679
|
}
|
|
1428
|
-
const data = assembleSettings({ provider, model, baseUrl,
|
|
1680
|
+
const data = assembleSettings({ provider, model, baseUrl, formats, timezone });
|
|
1429
1681
|
if (deps.saveSettings === void 0) {
|
|
1430
1682
|
return;
|
|
1431
1683
|
}
|
|
1432
1684
|
try {
|
|
1433
1685
|
const path = await deps.saveSettings(data);
|
|
1434
1686
|
writeLine(output, `\u2713 Saved to ${path}`);
|
|
1435
|
-
writeLine(output,
|
|
1687
|
+
writeLine(output, settingsSavedNote(provider));
|
|
1688
|
+
await refreshAiState(deps);
|
|
1436
1689
|
} catch (err) {
|
|
1437
1690
|
writeLine(output, `\u26A0 Could not save settings: ${err instanceof Error ? err.message : "write failed"}`);
|
|
1438
1691
|
}
|
|
1439
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
|
+
}
|
|
1440
1704
|
function assembleSettings(input) {
|
|
1441
|
-
const
|
|
1705
|
+
const outputFormats = input.formats.length > 0 ? input.formats : ["terminal"];
|
|
1706
|
+
const data = { provider: input.provider, outputFormats };
|
|
1442
1707
|
const model = input.model.trim();
|
|
1443
1708
|
if (model !== "") {
|
|
1444
1709
|
data.llmModel = model;
|
|
@@ -1451,10 +1716,6 @@ function assembleSettings(input) {
|
|
|
1451
1716
|
if (timezone !== "") {
|
|
1452
1717
|
data.timezone = timezone;
|
|
1453
1718
|
}
|
|
1454
|
-
const limit = interpretLimit(input.limitRaw);
|
|
1455
|
-
if ("maxCommits" in limit && limit.maxCommits !== void 0) {
|
|
1456
|
-
data.maxCommits = limit.maxCommits;
|
|
1457
|
-
}
|
|
1458
1719
|
return data;
|
|
1459
1720
|
}
|
|
1460
1721
|
async function runActivate(deps, output) {
|
|
@@ -1469,7 +1730,9 @@ async function runActivate(deps, output) {
|
|
|
1469
1730
|
try {
|
|
1470
1731
|
const outcome = await deps.activateLicense(key);
|
|
1471
1732
|
if (outcome.ok) {
|
|
1472
|
-
|
|
1733
|
+
deps.state.licensed = true;
|
|
1734
|
+
deps.state.tier = outcome.tier;
|
|
1735
|
+
writeLine(output, `\u2713 License activated \u2014 ${TIER_LABEL[outcome.tier]} tier.`);
|
|
1473
1736
|
} else {
|
|
1474
1737
|
writeLine(output, `\u26A0 ${outcome.reason}`);
|
|
1475
1738
|
}
|
|
@@ -1496,6 +1759,8 @@ async function runDeactivate(deps, output) {
|
|
|
1496
1759
|
try {
|
|
1497
1760
|
const outcome = await deps.deactivateLicense();
|
|
1498
1761
|
if (outcome.ok) {
|
|
1762
|
+
deps.state.licensed = false;
|
|
1763
|
+
deps.state.tier = "free";
|
|
1499
1764
|
writeLine(output, "\u2713 License deactivated \u2014 freed on this device. Re-activate anytime with your key.");
|
|
1500
1765
|
} else {
|
|
1501
1766
|
writeLine(output, `\u26A0 ${outcome.reason}`);
|
|
@@ -1567,14 +1832,30 @@ function assertNeverAction(action) {
|
|
|
1567
1832
|
async function runLaunchpad(deps) {
|
|
1568
1833
|
const output = deps.output ?? process.stderr;
|
|
1569
1834
|
const select = deps.select ?? clackLaunchpadSelect(output);
|
|
1570
|
-
const
|
|
1571
|
-
|
|
1572
|
-
|
|
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
|
+
}
|
|
1573
1844
|
for (; ; ) {
|
|
1845
|
+
if (repaint) {
|
|
1846
|
+
clearScreen(output);
|
|
1847
|
+
writeHeader();
|
|
1848
|
+
}
|
|
1849
|
+
const options = buildLaunchpadOptions(deps.state);
|
|
1574
1850
|
const action = await select({ message: "What would you like to do?", options }) ?? "quit";
|
|
1575
1851
|
if (await dispatchAction(deps, action, output) === "quit") {
|
|
1576
1852
|
return ExitCode.Success;
|
|
1577
1853
|
}
|
|
1854
|
+
if (repaint && await pause(output) === "quit") {
|
|
1855
|
+
writeLine(output, "");
|
|
1856
|
+
writeLine(output, FLAGS_CHEATSHEET);
|
|
1857
|
+
return ExitCode.Success;
|
|
1858
|
+
}
|
|
1578
1859
|
}
|
|
1579
1860
|
}
|
|
1580
1861
|
|
|
@@ -3165,6 +3446,8 @@ var FullNarrativeSchema = NarrativeSchema.extend({
|
|
|
3165
3446
|
|
|
3166
3447
|
// src/assemble/report-schema.ts
|
|
3167
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"]);
|
|
3168
3451
|
var JsonValueSchema = z2.lazy(
|
|
3169
3452
|
() => z2.union([
|
|
3170
3453
|
z2.string(),
|
|
@@ -3197,11 +3480,42 @@ var NarrativeSchema2 = z2.object({
|
|
|
3197
3480
|
message: "escalation must be present exactly when the confidence level is 'low'"
|
|
3198
3481
|
}).optional()
|
|
3199
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();
|
|
3200
3513
|
var ReportSchema = z2.object({
|
|
3201
3514
|
schemaVersion: z2.literal(SCHEMA_VERSION),
|
|
3202
3515
|
degraded: z2.boolean(),
|
|
3203
3516
|
analysis: AnalysisSchema,
|
|
3204
|
-
narrative: NarrativeSchema2.optional()
|
|
3517
|
+
narrative: NarrativeSchema2.optional(),
|
|
3518
|
+
provenance: ProvenanceSchema.optional()
|
|
3205
3519
|
}).strict();
|
|
3206
3520
|
|
|
3207
3521
|
// src/assemble/report.ts
|
|
@@ -3214,22 +3528,33 @@ function assembleReport(input) {
|
|
|
3214
3528
|
if (input.narrative !== void 0) {
|
|
3215
3529
|
report.narrative = structuredClone(input.narrative);
|
|
3216
3530
|
}
|
|
3531
|
+
if (input.provenance !== void 0) {
|
|
3532
|
+
report.provenance = structuredClone(input.provenance);
|
|
3533
|
+
}
|
|
3217
3534
|
return report;
|
|
3218
3535
|
}
|
|
3219
|
-
function reportFromOutcome(analysis, outcome) {
|
|
3536
|
+
function reportFromOutcome(analysis, outcome, provenance) {
|
|
3220
3537
|
switch (outcome.kind) {
|
|
3221
3538
|
case "narrated":
|
|
3222
|
-
return assembleReport({ analysis, narrative: outcome.narrative, degraded: false });
|
|
3539
|
+
return assembleReport({ analysis, narrative: outcome.narrative, degraded: false, provenance });
|
|
3223
3540
|
case "skipped":
|
|
3224
|
-
return assembleReport({ analysis, degraded: false });
|
|
3541
|
+
return assembleReport({ analysis, degraded: false, provenance: withoutAi(provenance) });
|
|
3225
3542
|
// intentional metrics-only
|
|
3226
3543
|
case "degraded":
|
|
3227
|
-
return assembleReport({ analysis, degraded: true });
|
|
3544
|
+
return assembleReport({ analysis, degraded: true, provenance: withoutAi(provenance) });
|
|
3228
3545
|
// fail-open, narrative lost
|
|
3229
3546
|
default:
|
|
3230
3547
|
return assertNever(outcome);
|
|
3231
3548
|
}
|
|
3232
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
|
+
}
|
|
3233
3558
|
function assertNever(value) {
|
|
3234
3559
|
throw new Error(`Unhandled narrate outcome: ${JSON.stringify(value)}`);
|
|
3235
3560
|
}
|
|
@@ -3644,18 +3969,87 @@ function classifyReport(report) {
|
|
|
3644
3969
|
};
|
|
3645
3970
|
}
|
|
3646
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
|
+
|
|
3647
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
|
+
];
|
|
3648
4042
|
var DEGRADED_BANNER = "\u26A0 Narrative unavailable \u2014 raw analysis below";
|
|
3649
4043
|
var METRICS_ONLY_NOTE = "Metrics-only run \u2014 no AI narrative requested";
|
|
3650
4044
|
function renderTerminal(report, opts = {}) {
|
|
3651
4045
|
const c = opts.color === void 0 ? pc2.createColors() : pc2.createColors(opts.color);
|
|
3652
4046
|
const route = classifyReport(report);
|
|
3653
|
-
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);
|
|
3654
4048
|
}
|
|
3655
|
-
function renderShowpiece(report, c) {
|
|
4049
|
+
function renderShowpiece(report, provenance, c) {
|
|
3656
4050
|
const { summary, explanation, coaching, confidence } = report.narrative;
|
|
3657
4051
|
return [
|
|
3658
|
-
|
|
4052
|
+
masthead(provenance, c),
|
|
3659
4053
|
...confidenceBand(confidence, c),
|
|
3660
4054
|
"",
|
|
3661
4055
|
c.bold("Summary"),
|
|
@@ -3681,15 +4075,77 @@ function renderShowpiece(report, c) {
|
|
|
3681
4075
|
]),
|
|
3682
4076
|
coaching.closingSummary,
|
|
3683
4077
|
"",
|
|
3684
|
-
|
|
4078
|
+
metricsSection(report.analysis, report.narrative.explanations, c)
|
|
3685
4079
|
].join("\n");
|
|
3686
4080
|
}
|
|
3687
|
-
function renderSubstrate(analysis, framing, c) {
|
|
4081
|
+
function renderSubstrate(analysis, framing, provenance, c) {
|
|
3688
4082
|
const banner = framing === "degraded" ? c.bold(c.yellow(DEGRADED_BANNER)) : c.dim(METRICS_ONLY_NOTE);
|
|
3689
|
-
return [
|
|
4083
|
+
return [masthead(provenance, c), "", banner, "", metricsSection(analysis, void 0, c)].join("\n");
|
|
3690
4084
|
}
|
|
3691
|
-
function
|
|
3692
|
-
|
|
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 ");
|
|
4119
|
+
}
|
|
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);
|
|
3693
4149
|
}
|
|
3694
4150
|
function confidenceBand(confidence, c) {
|
|
3695
4151
|
if (confidence === void 0) {
|
|
@@ -3704,25 +4160,56 @@ function confidenceBand(confidence, c) {
|
|
|
3704
4160
|
}
|
|
3705
4161
|
return lines;
|
|
3706
4162
|
}
|
|
3707
|
-
function
|
|
4163
|
+
function metricsSection(analysis, explanations, c) {
|
|
3708
4164
|
if (analysis.metrics.length === 0) {
|
|
3709
4165
|
return c.dim("No metrics computed.");
|
|
3710
4166
|
}
|
|
3711
|
-
const
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
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));
|
|
3722
4182
|
}
|
|
3723
4183
|
return lines.join("\n");
|
|
3724
4184
|
}
|
|
3725
|
-
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) {
|
|
3726
4213
|
if (value === void 0) {
|
|
3727
4214
|
return "";
|
|
3728
4215
|
}
|
|
@@ -3732,12 +4219,6 @@ function formatValue(value) {
|
|
|
3732
4219
|
}
|
|
3733
4220
|
return json.length > 60 ? `${json.slice(0, 59)}\u2026` : json;
|
|
3734
4221
|
}
|
|
3735
|
-
function maxWidth(values, floor) {
|
|
3736
|
-
return values.reduce((width, value) => Math.max(width, value.length), floor);
|
|
3737
|
-
}
|
|
3738
|
-
function pad2(value, width) {
|
|
3739
|
-
return value.length >= width ? value : value + " ".repeat(width - value.length);
|
|
3740
|
-
}
|
|
3741
4222
|
|
|
3742
4223
|
// src/render/html/escape.ts
|
|
3743
4224
|
function escapeHtml(text) {
|
|
@@ -3844,8 +4325,6 @@ function extractSeries(value) {
|
|
|
3844
4325
|
}
|
|
3845
4326
|
|
|
3846
4327
|
// src/render/html/svg.ts
|
|
3847
|
-
var VIEW_W = 100;
|
|
3848
|
-
var VIEW_H = 40;
|
|
3849
4328
|
function safe(n) {
|
|
3850
4329
|
return Number.isFinite(n) ? n : 0;
|
|
3851
4330
|
}
|
|
@@ -3855,99 +4334,265 @@ function r(n) {
|
|
|
3855
4334
|
function esc(text) {
|
|
3856
4335
|
return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
3857
4336
|
}
|
|
3858
|
-
function
|
|
3859
|
-
|
|
3860
|
-
|
|
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);
|
|
3861
4342
|
}
|
|
3862
|
-
|
|
3863
|
-
|
|
4343
|
+
return (h >>> 0).toString(36);
|
|
4344
|
+
}
|
|
4345
|
+
function maxValue(values) {
|
|
4346
|
+
let max = 0;
|
|
3864
4347
|
for (const raw of values) {
|
|
3865
4348
|
const v = safe(raw);
|
|
3866
|
-
if (v < min) min = v;
|
|
3867
4349
|
if (v > max) max = v;
|
|
3868
4350
|
}
|
|
3869
|
-
return
|
|
4351
|
+
return max;
|
|
3870
4352
|
}
|
|
3871
|
-
function
|
|
3872
|
-
|
|
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)}">`;
|
|
3873
4390
|
}
|
|
3874
4391
|
function empty(label, extraClass) {
|
|
3875
|
-
return `${open(label, extraClass)}</svg>`;
|
|
3876
|
-
}
|
|
3877
|
-
function
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
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("");
|
|
3884
4437
|
}
|
|
3885
4438
|
function svgLine(series, label) {
|
|
3886
|
-
if (series.length === 0)
|
|
3887
|
-
|
|
3888
|
-
}
|
|
3889
|
-
const
|
|
3890
|
-
const
|
|
3891
|
-
const
|
|
3892
|
-
const
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
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>`;
|
|
3897
4463
|
}
|
|
3898
4464
|
function svgBars(series, label) {
|
|
3899
|
-
if (series.length === 0)
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
const
|
|
3903
|
-
const
|
|
3904
|
-
const
|
|
3905
|
-
const
|
|
3906
|
-
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);
|
|
3907
4481
|
const bars = series.map((p, i) => {
|
|
3908
|
-
const h = Math.max(0, safe(p.value)) / top * (
|
|
3909
|
-
const x = i * slot + (slot - barW) / 2;
|
|
3910
|
-
|
|
3911
|
-
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);
|
|
3912
4485
|
}).join("");
|
|
3913
|
-
|
|
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>`;
|
|
3914
4488
|
}
|
|
3915
4489
|
function svgHBars(series, label) {
|
|
3916
|
-
if (series.length === 0)
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
const
|
|
3920
|
-
const
|
|
3921
|
-
const
|
|
3922
|
-
const
|
|
3923
|
-
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;
|
|
3924
4510
|
const bars = series.map((p, i) => {
|
|
3925
|
-
const w = Math.max(0, safe(p.value)) / top *
|
|
3926
|
-
const y = i *
|
|
3927
|
-
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);
|
|
3928
4514
|
}).join("");
|
|
3929
|
-
|
|
3930
|
-
}
|
|
3931
|
-
function svgGauge(value, max, label) {
|
|
3932
|
-
const denom = max <= 0 ? 1 : max;
|
|
3933
|
-
const t = Math.min(1, Math.max(0, safe(value) / denom));
|
|
3934
|
-
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>`;
|
|
3935
4517
|
}
|
|
3936
4518
|
function svgRadar(points, max, label) {
|
|
3937
4519
|
if (points.length < 3) {
|
|
3938
4520
|
return svgBars(points, label).replace("chart-bars", "chart-radar");
|
|
3939
4521
|
}
|
|
4522
|
+
const id = `cw-radar-${hashId(label)}`;
|
|
3940
4523
|
const denom = max <= 0 ? 1 : max;
|
|
3941
|
-
const
|
|
3942
|
-
const
|
|
3943
|
-
const
|
|
4524
|
+
const W = 300;
|
|
4525
|
+
const H = 230;
|
|
4526
|
+
const cx = W / 2;
|
|
4527
|
+
const cy = 108;
|
|
4528
|
+
const radius = 72;
|
|
3944
4529
|
const n = points.length;
|
|
3945
|
-
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) => {
|
|
3946
4538
|
const t = Math.min(1, Math.max(0, safe(p.value) / denom));
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
}).join(" ");
|
|
3950
|
-
|
|
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>`;
|
|
3951
4596
|
}
|
|
3952
4597
|
|
|
3953
4598
|
// src/render/html/charts.ts
|
|
@@ -3978,151 +4623,74 @@ function formatNumber(value) {
|
|
|
3978
4623
|
}
|
|
3979
4624
|
return Number.isInteger(value) ? String(value) : String(Math.round(value * 100) / 100);
|
|
3980
4625
|
}
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
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;
|
|
3994
4652
|
}
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
case "E":
|
|
4004
|
-
return svgHBars(series, label);
|
|
4005
|
-
case "C":
|
|
4006
|
-
return svgBars(series, label);
|
|
4007
|
-
case "F":
|
|
4008
|
-
return svgRadar(series, 100, label);
|
|
4009
|
-
default:
|
|
4010
|
-
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);
|
|
4011
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));
|
|
4012
4665
|
}
|
|
4013
4666
|
function groupOverviewPanel(group, metrics) {
|
|
4014
4667
|
const description = GROUP_DESCRIPTION[group];
|
|
4015
|
-
const
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
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)}">
|
|
4019
4672
|
<figcaption>${escapeHtml(description)}</figcaption>
|
|
4020
4673
|
<p class="chart-empty">No chartable series for this group \u2014 see the metric cards below.</p>
|
|
4021
4674
|
</figure>`;
|
|
4022
4675
|
}
|
|
4023
|
-
const
|
|
4676
|
+
const gridClass = subs.length > 1 ? "chart-cells two" : "chart-cells";
|
|
4024
4677
|
return `<figure class="chart-panel" aria-label="${escapeHtml(label)}">
|
|
4025
|
-
<figcaption>${escapeHtml(description)}
|
|
4026
|
-
${
|
|
4027
|
-
${
|
|
4678
|
+
<figcaption>${escapeHtml(description)}</figcaption>
|
|
4679
|
+
<div class="${gridClass}">
|
|
4680
|
+
${subs.join("\n")}
|
|
4681
|
+
</div>
|
|
4028
4682
|
</figure>`;
|
|
4029
4683
|
}
|
|
4030
|
-
function metricVisual(metric) {
|
|
4031
|
-
if (metric.status === "not_available") {
|
|
4032
|
-
return "";
|
|
4033
|
-
}
|
|
4034
|
-
const label = `${metric.title} visual`;
|
|
4035
|
-
const shape = detectShape(metric.value);
|
|
4036
|
-
switch (shape) {
|
|
4037
|
-
case "timeseries": {
|
|
4038
|
-
const series = extractSeries(metric.value);
|
|
4039
|
-
return `<div class="metric-visual">${svgLine(series, label)}
|
|
4040
|
-
${dataTable(series, "Value", metric.title)}</div>`;
|
|
4041
|
-
}
|
|
4042
|
-
case "distribution": {
|
|
4043
|
-
const series = extractSeries(metric.value);
|
|
4044
|
-
return `<div class="metric-visual">${svgBars(series, label)}
|
|
4045
|
-
${dataTable(series, "Value", metric.title)}</div>`;
|
|
4046
|
-
}
|
|
4047
|
-
case "scalar-range": {
|
|
4048
|
-
const range = rangeField(metric.value);
|
|
4049
|
-
const series = extractSeries(metric.value);
|
|
4050
|
-
const gauge = range === void 0 ? "" : svgGauge(range.value, range.max, label);
|
|
4051
|
-
const spark = series.length > 1 ? svgSparkline(series, label) : "";
|
|
4052
|
-
const number = range === void 0 ? "" : `<span class="metric-number">${escapeHtml(formatNumber(range.value))}</span>`;
|
|
4053
|
-
return `<div class="metric-visual metric-visual-range">${gauge}${spark}${number}
|
|
4054
|
-
${dataTable(series, "Value", metric.title)}</div>`;
|
|
4055
|
-
}
|
|
4056
|
-
case "scalar":
|
|
4057
|
-
case "none":
|
|
4058
|
-
default:
|
|
4059
|
-
return "";
|
|
4060
|
-
}
|
|
4061
|
-
}
|
|
4062
4684
|
|
|
4063
|
-
// src/render/html/
|
|
4064
|
-
var HEALTH_GLYPH = {
|
|
4065
|
-
ok: "\u25CF",
|
|
4066
|
-
watch: "\u25D0",
|
|
4067
|
-
risk: "\u25B2",
|
|
4068
|
-
|
|
4069
|
-
};
|
|
4070
|
-
var HEALTH_LABEL = {
|
|
4071
|
-
ok: "ok",
|
|
4072
|
-
watch: "watch",
|
|
4073
|
-
risk: "risk",
|
|
4074
|
-
na: "n/a"
|
|
4075
|
-
};
|
|
4076
|
-
function field(value, key) {
|
|
4077
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4078
|
-
return void 0;
|
|
4079
|
-
}
|
|
4080
|
-
const v = value[key];
|
|
4081
|
-
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
4082
|
-
}
|
|
4083
|
-
function higherBetter(key, okMin, watchMin) {
|
|
4084
|
-
return (value) => {
|
|
4085
|
-
const n = field(value, key);
|
|
4086
|
-
if (n === void 0) return "ok";
|
|
4087
|
-
if (n >= okMin) return "ok";
|
|
4088
|
-
if (n >= watchMin) return "watch";
|
|
4089
|
-
return "risk";
|
|
4090
|
-
};
|
|
4091
|
-
}
|
|
4092
|
-
function lowerBetter(key, okMax, watchMax) {
|
|
4093
|
-
return (value) => {
|
|
4094
|
-
const n = field(value, key);
|
|
4095
|
-
if (n === void 0) return "ok";
|
|
4096
|
-
if (n <= okMax) return "ok";
|
|
4097
|
-
if (n <= watchMax) return "watch";
|
|
4098
|
-
return "risk";
|
|
4099
|
-
};
|
|
4100
|
-
}
|
|
4101
|
-
var REGISTRY = {
|
|
4102
|
-
// Knowledge concentration — fewer key people is riskier.
|
|
4103
|
-
"b-bus-factor": higherBetter("busFactor", 3, 2),
|
|
4104
|
-
"f-bus-factor-risk": higherBetter("busFactor", 3, 2),
|
|
4105
|
-
// Contribution concentration — a very high top share concentrates load.
|
|
4106
|
-
"b-contribution-distribution": lowerBetter("topCommitSharePct", 60, 80),
|
|
4107
|
-
// Message quality — higher Conventional-Commits adherence is healthier.
|
|
4108
|
-
"c-conventional-commits": higherBetter("adherenceSharePct", 70, 40),
|
|
4109
|
-
// Low-information commit messages — fewer is healthier.
|
|
4110
|
-
"c-low-information-rate": lowerBetter("lowInfoSharePct", 10, 25),
|
|
4111
|
-
// Workflow discipline — a high direct-to-default share is riskier.
|
|
4112
|
-
"d-direct-to-default": lowerBetter("directToDefaultSharePct", 20, 50),
|
|
4113
|
-
// Overall hygiene composite (0–100).
|
|
4114
|
-
"f-hygiene-score": higherBetter("score", 75, 50)
|
|
4115
|
-
};
|
|
4116
|
-
function classifyHealth(metric) {
|
|
4117
|
-
if (metric.status === "not_available") {
|
|
4118
|
-
return "na";
|
|
4119
|
-
}
|
|
4120
|
-
const classifier = REGISTRY[metric.id];
|
|
4121
|
-
return classifier === void 0 ? "ok" : classifier(metric.value);
|
|
4122
|
-
}
|
|
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,d09GMgABAAAAAFxwABAAAAABBWAAAFwNAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoFQG4GvRhzVcAZgP1NUQVReAIU2EQgKgbtAgaEUC4gOAAE2AiQDkBgEIAWEXAehBAwHGw7zJ5huOl475bYBtOPXkPVLdAHVazeH0HNrHDdaqtTZgdrjQMa0T/b//2ckqDEGwlsHomq1bYbCsDBcZiTWsxNV1a1G2qzqFdVZ6UNgIaKzpsNF5bDt1lmK+4wJAuaM6cYjQYIECc2vCjsyLghJw2P1Eb2H+sS5+Wk9BoiB3CSejPblcoR+3ffTTvu8/ve22xfN0DQ85cPFRX+v6vG6z7bljR/7xPmXScNKt68ouQqMXTYjYtVJX3rAuh7+66STnrmP1E7SN3YCVwSnf56v259z35sxmzEGQ7KMYU+S7PklhdolRUQb2oQ0DBOTtMuv+b5la5Lk+6Xla1o22j+jVcumkt/XLmNLG0Og5/+VmlXaGqU1ahZdRkpqRrasQUJEkIREEBIhEYmVCLGrVtWsGKWLDtTqmr/RVsd8Y63PP3z7Pez3GXkXT5AISTwkGnQWVURDshJo5df4053//92se+ER6L1RoHLOsGPmXzuRppkpdaZD6yNJ3gr80t9VFWRNfPs1e6tcO75VdVWAcAuc5C+wcP4wslWW59soiILr/522W/u3vZ10zaQzt6dGKIzioZASo5Eo/BnDWH/pvv3rECuvT4dWnqFdxIP4YtVDNNsvJTM7/UN00eqlPPIQPZPFTjQfC7N3nkPsf6fN87AoixIohdMo5NrdI7dy7U+a9nZuT2iGwmr7AElOl1FUJ9bKOYx/qAv91ZQ6c5qdw+Vg/MY7fl4qhyNSsYxHrCj7oh6qOBiI3u3svWAaiNV4U2FFJ4hmnqBAcgtlAAcjt3+u+f2jlywXje1kE5ZsbAFYu7tStUqnRaIW0FmsI+8810rvbKq7N8YH6cdjAAGDIbQgSN0TpHhHroe4erkz5Jo6YqndorjvvCHXUuesDZI3PvrU+ujz8Ez0zqbxp/Gn0cPz/Vqf+v5Tk7dAXR0Yl1qhI0xXTyL9QP9NvTkDAe6E1V9AhdAL5X/FAikCR45AhXWMidARlq3/zbTsztsri7qQVoVx8DcNJvWTjjuXUlWzMv83VanHvCRthYILS+BYAxHbJ71f6XpR54RrAJLvfyd5SO7YC8C+Pl4KS5lk5LB2y8WkBNSVaV79rM1jr/HzvKCxgI7nEQnBxoKfSEAwdRbQ4+H75Tu7J6WqLyNv3JsY16TMzNufBLg8Wl+qXD50FUer44mxKGSMxP9v2u9TajK0prrtxhDhWKExZjN3XibtbfbM7vzej6e0WVoSqvyLQ+KQYNG4qgyeg0VpjsdriCbHv98RBMItjMg5dReew084VSidCjFOzP+cKrX9rKyl66kDrUGIzQofDKKR5ChD/wrXxL0C2rKUFRqzwteW8ObNgF7MQSSVjyxhsRL+sdR3+yL3vWzPY5AiYQgiIYjYIEOZnt9l/b8R/b/TsEHDjG+MtdZIkitJkiQZGVlrjb8NZ4hW2WUMq1jGmxxjM7fBslyUGwroEWV+GqpLXVxw5Vq/hQCGEf8qFIIPwLciTBFKKF89pPYYeuol1O479MsQjCABjEYGYDzkAcZHPcAsE8Nss4MFhYHNigRTag8r1hNWpi+swomww06FHXE67IIrYQ2Ww5q6iaqrLzBtWlT99aMgAtwKuBbErKnmNLWkrR/CbkLgGkLko5/0lPUZnp9FCcHpqxk7hNP3/ZnAFA04DhswUAJV2GEc9ebXJgLvw3L4vu4O8Q9l/sCmQBhusXfbQBuvLmC/3b9xpl/Dbz/UAnxMAogD4Z6TK9yn4GGwYEKIt5nBwWBoYe/XfZjquUFfUcNYlQ07+mHB3W/lhGsILw4jeYkXf3E/4cVZN2Vn2iIs9IJBjOq+XKY4LEnabImko5lgcRiS57xwYXf5C0Z0LQrEgCojP8JBg2QEVeCsP8VJBoyn30MHTUXo+RhV9DArpkJOoZdH9q1ySOEUTcGB9BOYwkIl8pKK7wL7seHqbIZo0ZjnaSRC/SwmX8OogW02q95gbQQrWJCUlxfMmjK14Khau6qZFSuaUs1dRbMtU/w79riSSa4NCcdb2hgjDfvA4YGeeFwuoppaSYeNDPKFm5WXu/g8i/Xi6SdbOKqcRzEpIP/jcKsrE85lNpXy5qIjcSDVe4WG7zGcKXg2+1GnRqUyBeI1WrrbDjlM8C2ipiAlxsflyLHQEKDBxBgKuXQiR/+B2zVSB9e3FrhCtv2w/GuGyV8oscN8SznYUdzaj3K9+Lza4/pOHH9eMyXISWZbEbc8bb0wahdNZ0zlv37U9ZqAWkSDY6qOyVsQGqtFgBN9nFi7aGue6MQ7Jmvl3nDcRZJMOpwQXUwCSxpSkibiOvXHGNZGqwbZXXZ7bvCUe0Rtv502qjch0CrZR79TvZoWCzM6mtHjZyVvG6OIKEQhClGzoOXOOItxJ62cbAfS4Xc9SJcIcWlU7kRFgYctXyNi/HD6EwAYKLQxGjx36s7VyaYN0dwQ/nDUQhzSNDfIIlB5gpK7iF3Mq5p3sqJbwS+lA7mI07RokLZAkz6hlKVBuKSXfFNMMogDccjVtOiNDWD0G3sk2GQ3KDuqjScBMFBoY4BrfNRzQE835+Vyah4NDqu9shKRizhNazYDYSi2XgJkz99bjrvjMU3VxH08RR8G8BXf+L064qcOOQDO0m121plNXfwRC5jAw4Y8QO4ld5HbvdwCxs2bmJVR9l5VE1+JOXf1vLOe9LfVG9iwxTy3T6NrjXfRMbitfDTuohn0iGs0cDmdv2PT2WSHQF903t4Wvks7oqZOjWKQNMTw67kla9AgDEaXsBHTc8clzRzMj+C5RFszIKoXwLmB3ohDdYMrPd9glPmmztp7NhrCsSco7htH6fTq9siIIxNW27xFoB9jXgjiRGhMXwbUcXX7clmcfcV8yw4QCgncS+PtxW8HjV4dyZfgsumIYhzwJ0cDCpzWc+WmxQ8WAfl68GSpARRs0JaCNV6Cg5DhOgZuBFJ2xZXfY9BD8IDr0cdlxI0ud/OMssAuM+yhtEm+ApsVq7ct46niAtdpsTOzfdfKPvYBtonR17SrC5JzH0OABjam6188olpdfhJY8+U9QoC60X8YqsAHxnW3RIMbvC2YDaO4WCZ32U5IunP1vtL59UGVcFua6WlFMSWT6i/hqL/wpxMzzPYvHba4G8NF7ep+6zW+70ebhFv3LLp8mSfKJrhVZaR18iJyQbmuBVorzc4VcMhTez7eI0yiv5otb05YUnkbYUREeCsT4kptWCzBCWNacyLKS5an9yY0zWX1QgQTlSzFtrhr+/Kx5nARvSzdJnLtIhKXYdePFy3b0ywzrv5Taech/fJ5WLR0l/OVFwBtG5FE8nELnYzfahqAOP4BOcHBQhDDCHg/i0aXPa1nk/mroD01vDAI+i166ra3SaTJUrRwwu6DyxW1UBDv8+hAboUbHW5PK0ziHWyxzq/dWBj5Iqr/K5djVwlWu9H/2jJVHfFxv21E/Ho5auu73oUpPS6FI0z7uX7iF47SZ6qwKT59sm7zMzdEwacZg1kjv0nbu8mJKC0IyXcuTfwZ2A9WXvUpXIlFMYGKjVxgZQXcrOFli24Od/HzyI9eAeEZN+vCqjmHJIXFdCg8lk9FxWHf4nI5troCbiUl55msSn5l0ze5Bq1Nr1Nnc+vSV2j9KLwBRTSshY1GFNmkqaKavhTd7NvFtGCxxZl7aGkfeiMOEeJF3KFG3tpQjhcBwihgGg2cYwDLmMAwFhDGBo5xlmDjXRyjPJA884J5A50PmC+k8WB+0AWg32RMCoRfMPymwW86zMIY1XyowpEUARYF3SKwxdAtgdvSm9gtKwen2PivfFyCR+LLxWp1EjqtrQijZMDWISoF49bXV16aPFpWGVJ6Spgc6DaAZULKAsuuk9+kprcZ0W0RtrWe5bepP9ypMd12Ibo8WfS7mO2WoD3LdCMYG1FD5hVrdCWyqlT2lcmgco1sr8SpZFRlzc0o75yq0jJblIoeZh9u16OewJ72DMGZ8cUGK/gYQ+GAkSMii+3wtYeLXDBOaViwZMW6ibIkvk1kIYiONG9KSAIcrl9QaIJptIqpYcexRv8hXjP6vVhZAUtW9Kv26sRdEnEIunDgogsHdjDXCtAlIQ1GYsZIzJpYS6I8ie9qZCUxbaKJHgQxPAzRg8ISJxhYa5KrOGKKHSYIsUCSHNWghyr25sgh5IIGbqD9rd1whdrRma2Wv/K8Vb5NpjSxFnDISBgihTrIQjbOL7WnuMEMOvU6ZcZ5epOK4IaTdSzoOwMz7zArOzZVE0xicZKw0iyQCBlkF8a+DGHzBaLTGS7HHR7LH/TzwCj8uKIUqMbA1uqD5Q8kGZZOFMANdRhIiO0M+nTxOb4ZBKDzWSIADdwqlR4d6ojrgS3moV3okCSWx9d61JQGSKDbIZUqjXPHLVeHooiSAjLzKrL4+rk4sUnhSo1X1mUhZaQgaYoMW51Ak2YtWg07bYXyJYeWdaj4Ewno+sqUl+6bogOjDGniwQxpM/3IsGU5HMRwzHrYsOG2AnvYUo47SOoh48H5xBpG1cibF7Sanfth0bGHoQJA6IUwlFNMr46ViE87Sr0351mRGxrHROgp4QEYeOCZqC+chQfiJ2IF0J4oW6GcIydqGtfuIbNjY6Yz7OPKnKhhaIdRunUNvyvB418idxTYYt4UsPqMlhx4czzzSL2RwY3tL7vU0fv8n9NDMz4MQ3z9GbnjFwMN7vrhUjgEmQRJnmPPX6an9MPTRR4Icp4XR7bHQ0QOtu6bZX1Q23ld16T6S4I55wCghu66/jl47UAMxvWth2g/pz8RZBhWp7KT2Dxmrt7otztP6sWUS+fJS/wm71oEhfKpjDJtJAtyhHB3OxUBOzpzP8MFRgPiaxXjltXrvhDgWAw45cb9bXiM57OXQ5PXf9yuvRcoN005dkhBiHQdWcsyQOX7svD/ADsr7V27hUTeNSbWC08c2fW2J+TIfjAdqzL5Jvhp/kt/yaNbc0wy7eo7S3ozUV7S/xnVMIlqdYhMsUTD9AqSbkQSjNUj8FlHJBiUU5cOafWxk1QtJDFzDHgqGC3PHdlS03ZCM9CwW590kPFSZJGjLtj6MWa50dae0CezSr/9/lCT3HAG0ekC526uVgk2i4WQCaykCAzXDditxozRlsB/MNXshtdKG12QeV009+hcgmAynnwiJAQpjuoY4CvV0Tlx1vxVcXQLVU8cl81XX3ZJAkQ+6eOgh20Zagh8TrqmzSWdZAh+t7qlG9oxEwCUKNDydVQvf8TlEEF2CVwKeJlfNNEmFnqTqM53bhE3lSLN/IB+qm4pIiTORWVXjlUf4XffFzHxLdzDldV+6TPTDxwF6V5C1ZMbhaLMBAUd7D0Joc9WUVmQrub4xzXWXtPLW9U1Qdh36xXDHnT/wBYIP7xdgpcpsNA4bEpP3oU69Kto66vlq1Zmf6rfRbGlmKLb6bH+v3jUWrBzJER4FpqrJz/wG9U0C+2cx+BEXvuf7QqlkpCOkoRGHRF5bF1g6XXMEwy4TKnWcx33NuIkAwFyZFurxYhbB4f2hrvZGPs/FQvJJIbEygM+2ZUPjbnxk43NriBbdBrGgLhLT2/1CkcH0o/sMflP+u0+1e48ZF/PVh8268z3NWnzi1516Weyv+8Ij14OuxucR2PD6C5WqVoAMOjSFFH2rd/7w2UwWDAc2FMiFXhDnH4lRF84AKef8oDkfWZQB898hQp45jtmTbr2jexmJ4+476v/ZzXL/YW0yPuecrSWq4qz6CoC55gEV5ZOtkdgJjn/r1f8j87Vk3eGi2HER3h/Pu4t/udBdOFrr6H7ffSBG1i9C7ifDt9Cd+pi1Tuof4mwXyy4JLMuFuAkFt3lMqhR3X+/owGqzsQUlJtXiOLwcmXsUp1Ct7xaeDpEh1mPVbLvhsnELfB08OSKbbZ74N0aAMZicz2ZlEIdRiK+f/n/GfItghT8jIFMGIqNXAS8fTcotDZotDUY6OAwR1lZOiwnlgdrF2s3y4vlw/JlhbIOsiBlsYc6wevCIDXrkEdTWSEHC+s7/ldFILYg9DAI6ENChmhGJJA1WzQ7jpCTUQw5Gw25cGVoLDdonHGsuZsEBZiHFmY+tMACtHALoUiL6IsWQ9diCdjWSjJCMilzqdIIySjwbLSJSI7ddOzxB5RvH6JSJRv7HUBUq4H+UkvP3w6xcNgReo46ysIx/9BT7wQTaueg866gXHUbccddlHvuIVo9QHnoMa4nnkBPPcfU5iWWV16ZoN3/WDq9w/HeZ2a6fGGq21ccg74z9sMP6KefiF9+8TVkiGMECYyJQgo8YiADvGIiE1xjIQvGxEY2TIyDHBifJAmrbLJhlV12rEaau0nrQTDwCx8j+AjgY4SL40ZCGYUzo3BmFM4PWTbTfVbNHj1FSJQxwx8DfYaC4WMEHyMcsMUOB2yRIGYkfMbixljcEMDHCD4C+AjgYwQfAXycMMITS0Yf6ZTS0ewHSXUfG/W3YVD9RnrhTwV5sZF3bA/eHl16dLIDYYzIIj7OmBUdEhKjM0XzHNFk0mQKVvY8XPPiw1QRmud1dXKkaltvCAsbJFXjsPh2uxB5drO3RwFUbB/MFCwxg8DGDnbYDQl2eYooSHsXZgdmcOBXhVBMhoKLFWK4GuQFyCTG4Ys13o7PCKboPRaNL7qgUCmrAgCuAgBmxpoRY0aMGTE2HpeGQqGcMCQAwAAYRkgEI8TXG53G1c0OgCUrltUVAK5CFQBwglL/AEMwW2ImDEmmRuXY9GyCKs8+C48xLo1VvP30H2NoWsuUeWIcVUV46C0AmMm6J+gPMRe/b3wlOcD39sMfAnh79iMmdHgfonzzhV/cV6iMdVMk33+w6eItvy/v0Ct8oXLy/rYM8GhdE9yKJvRq2Wh9XiYxyL+jYyGZgthOO41RqIhrDnG3suIJ7k47Z0J+eAGG+17mnpwNCCqV4KRMTbE0LTK76Rm40QxzCATSr7Z1sbaOrp4+BBNJZAqVRmdzuDy+QIIZGhmbmJqZW1haWdvY2kGOMPOFi7DQHkp/qHZQjb/UOqzOEccc9w+1k0457YyzzjnvgosaNLrksivuuKvVfQ888aMkUk9aWslHgM207E7OrlzDNV3LtV3Hdcsh+kgxJcvac6VESZF8TOukWE9aUp4Cv+N3f+/s8yUyrn013TMwAd/QDukDMIBvNQHgNHDQpwauUcytw2F1jjjmuH/UO9FoSkfPmO3t/IhySPcwBCAAbev/7zw323VOqTvVsKwjDUs+OErX0X05OpBbXxzs+3H+rkjmNrNGpygEHyhKtCNisXBIlVOqUK1GHb16z2x0z6+F7vW31LNFZT3Oo4+9otZNh5PkZLhP+/f93a45ea7sF3rdUewunz6Rbayeda3GdC6mUwt5cFvGwn0DUFeUTktcipaglmym+1JXXd9tk7dnW+UWb5xPChpNo+Hu6Umtf8+cPDt+riiERPkOHMkwjg9mY/FtdIVZwEK0TaxUqhRU84tgR5xW5x+e7oyLWRq/zWzXXDfHEy/N1e6ziLptfEv7UGKJ6ksq6V7JRc11VcuU0kaqabXoYVn1mF43lH+T52gFFtnh0gcnkUFuw7vJcvCJxUj56OSOJ53Nhb8AgeAQkFDQMLCS4eAREJGQUVDR0KVExv/zcDNzJQ9ZsuXgExDKlUdELJ8kCmhIR0qUFPWuO5Gd5Fu8002rR68+/QZ8vUysXzYuPrUAAAAA1aSRekxpITtCugxyG2TKooiNR5dtU6lr7aESJUXqsaWF7GDpMshtkCmL4nsqJhNd0RlDdB7srXe6afXo1affgK9TA6oSaw+XKCllMdORQW6DTFkUl+1CUj/QdFUkH2qdFOtJQ3ZAugxyG2TKoojOw731znsffPTJZ920evTq02+g+1poG9Kuozv6JEukJgUaA5MOFjYOLh5dfHrGveMRhBNso+y26YMlyFSF8Cj1+njTsag1XcJBXtzlqDVApR8A/SlRnwMlhlk10pLPqJpKLvgcw7oqkeg0BR0yF1FfnEjCYeVKojfnZpgyUuivKi3/YtMcI/HQH5b1G/h0UfLDFupb6Wj02j5M6sU28zaQJqqOA66th7qeT6eTcAfTo4Tzpn39AUvzY8p509w1ouRg11yPtsO98NIr7V7r8J83/s8PZ7QGfeu+TwP+BOPAOkQVWvp7mWFMelbyZXzw6iwi+UTDRkkPfRxCOjUxpe18ZSyf/PpxZ8vG0bVejU6+t4cfMnX7FC20K8SoHdiO+6NsGCXI+LikL/iWrYguX+39fD4b+MTHn1uAA47DudIuqC+Yj/lEmk7N4zdivfqVlCHtM5MjJH4uirHyy0Q3Mf17ZRKm/Jhzggk//3kE3r9vupnqBBxhhgLUyb02Fg4ePgEhQyImTJmxIAayaw9xxkwS1uzYG/VSnWOR5I2kSpIjWbbY2uoHLfMtt1jGLoBY8i/FohvuwlHIhVjwQ0LFvNO8cvo/BOaV5vk8yjVfXvPSNVX/mwkfczlABATCQiQYFw91kY96KEg/YQYZZtTIzLJMnHkWWSXJNruss8k+h0QZZ9KITHPMqVE5NzqXxuTa2MblnkeeeeWdT76Nzy2/fmsCghNBLkBPKhmnGVEIiohF1KI4jFtdPpPWVsS01PSZl8vYmG5121h3aZexHWn908wMB7mm0QoqPGkhQ4UtOXSY8BEiR4kYKVacqrlfVnnKuv6K1FXWSJO2qhMlKaPr6OgZLSLyAePhBGC5OJtNmwnJrzFSTtWHnxG3zApJ/lj6UEf/9ab/6+xt73rfhz72qc8IHV26QE8KB4soHau1FeCVWiXdcjUmqrWXjDGBJ1/L38hn+ApPjFPMicns2dv2a/uh1/TK9+wdt4ftQkH9ayIsQQcl8M+CJgiBIQwo4EMhBh1VLlF9ay/Y10qmmHCEhXlXcDzJk4gmhiqHnaF+KikzbpDkStDtmStqKVHIVcWrOHQGmQXPRuBuNtTMfHV9xKFKZK6Uppc9sQjZbXDXxHAkhRIPI9MfDQfV/V7GI/To7m+pmt1T3sEfXtkw54rfWfZZ7QYpmA4Y6jz4+HYEdSFIFHIBujYa3RWKzrq0Huhy4LxxQLE3c1UhcbF519o+xtqGxE1tXfMy9EpA4lxalxSMvMISJ2rXsDdyLdgsF0reDAieaZkCCJR15xCAgMLMNwACse15EyA4c/ec1+ZxAIH2wZkPIHglTwMQrEkXAQjmxVMAglJIMOMDIKGGw6dmYDYj6kEvKfN0SqzwuCnSH68nenxuLU9kQ9XXwd3hcHoZ1jr0JOZ24eADEYa0WUMNzK76DqeRWtFq0PnajrLGDama14eeK8wQqjRz+tDhNEQRu3D4kT+P6bVXZFDdn3mkoKchYLcVvxuCgwZCj1HoOl4lLXrfzBvj74Uvvi0x46/ig3GAxEG3xwc0ALPIHmjq/AbxpuuBDUPrNP8U5JX6HWRp5+Cp4JNFHRIsqOY7GlSHbmYJZbYLZeEQYAGWcYXtmncoesVE4AJs8Reh2HX7cRqQfOhTEUL3woDdqi6HMO5sIRAxWo7jxe/00pivrCq5qGerLJnGxRdABy48jIY4in+7CZwaPz7br27u40qOiU1W1jF1XzfxyMquWGn/6fAi6cEceq2VK5W4BDi/YTa7I9LVHELbzZPdIQDyA8IkBrxhu2NGfQs6M8mPDB5jWPA2HoSqLFq4Voc8EC6sC3Bh1MBBCOTIPweYxtSuFDmRVL2MxIEwKBfzAGQ/UorOyHakRdmELCRNdUpsDyVpQf+uHd0D+vjPg7oXe1KtqJR5pWFhIdBlsvVIwYnqTa3GEtlzqU6PhROxcRQsXTElDclqVr22G8KMofzzAiNA7CJil1Z6G9Eqq6HrrP229g9OgZVfPFhgtil8ORAheJh9RNq4zdMOfOCrA4iu7cnzH0J56RENoTpVSuy2hVyyeDHU3y/IBJ5c2EVgoDeoslXtlM1l7yHzG9lcy1DMZSxk7bdo06X2uXrcrmxVZ3uyJEuyFdkRGByI49/yeuflyov7+tKFyR4yXn66gg5vrhxImBERBClm0RkO8Rji/zn3qIe+2G9cnvfWmo9Ypf6M1FTF3P12riIqCN21oMNrsUjURihDOUVE1yoF5qpTCDdi/N+JqH7cBwLufJgWYrp0p6wJQeIJSBs1Ik4OUyhUMdVCYHLClNGNs4gv2Gre60qJ/r8S/0v/9vTo78vv/R/ht/p0SHHldV3T1Vz5FR7/0o5y6Is7du7J17rKNdHALpYv2+p6q+zZNW3/dqxhNStf8fI2ZQkLX+iGay5abgtX/ze7mUx7YNBYI8z0jEzPtEzdqEY6wuEMbbCTMMMho05nalfj/F9dddCiuEG1nu9EB9rZxlZVUUmzyyqpyMY0rl2xQkunSw6ZpRuacpxIOZ2T6Utb9FGnJHnhhhFcYImKHz29NE5z/x9vPHLTiSMbnvOUh9zlJte43IXmO80Uox1nZteyW67sUgNaiIup2jW9aZyVSf3qkEEaySUWTykiCC6oQplC4lSY/8eOCW0AhIXANCP00EIdKqQI4UADSwJDCCodalM3hBrcaoMVwwumXQGdqVOtYLnLXtokyx5rpCEXMzYyfWjCKhQh3+3M8HrxJhCHot4hVcrky5VDroRYtjQ0OHAxGEKHtDQIixDsONKeddtzdCXdNuV2I7T56ZqZGUmSAACoqqqKiEgyHzgPNDcboZXNZ2ZmZiRJAgCgqqoqIiLJO3eYEXphZmZGkiQAAKqqqiIikowhJkmSJEmSJEmSJEmSJAkAAAAAAAAAAAAAAAAA5CVJkiRJkiRJkiRJkiQJAAAAAAAAAAB4/DJL2FWjXwcDTfLE8UqJEDxoLtlkmiAm/NTjnZce0LjklDpVyuTLlUMuxWrLRAozu3UkwLetTvOUy9UdWUoRy6wEmGVXIUFMpJIkSQAAUbS5GY1MN2reDbuEDUemrrMaRciglYECFtDUq6VSIFe2NBLZWEiQYsRsIkEJhzoElfPSUleX5O45vm2MNCUiBvXw1x/XRfLkSFeILw0FWhzGJWupEMD/aBGPVc1L6Xg1VZSZPEn8ODHCnvf4tTPRBhCLoE6VErttISclxEGDlWCIUHXUCMHBVg0qwgVp1VebqoJyyy4tSdmxIoUsrmF+ZmKtakjDT+lS+uxIG9s4Utp5jydyYjwpCOCgQiaEU8Cf7ZrUDkJZCdVVVUm725I8acI40cKW0DCSWqcaEhjU5Y1n7rqhwSlH1VApsts2Csuhxb/i1T+AHxzdpUlKSIXAewoeUiG4+9/c93M2QpOZmZmZkSQJAACNSZIAKP071B9T2XwKCTrjin6KAmJNDJtW9kBpGtjN2SdBYb7tpeAM6PttLOf9wO0h7JZyA+EzUwzwR2+LwEpNBfMHB20/cfJbVRpc7dZ6r3YXOwEzVtTd0prx/jPZvfnq1N38ZQo6GnBvO0TdTQ9EYCqBn0Tdjfe5Y5DCJlF3wz1CtFBYI2quf8joQXHDbaLuuj4Yb3Wl8NqBLA5b7LVGxtH0307/AvHPd8ZZ55w3a85l8xYtuOSCi4QzRYz6wDXH0Tkj2rcOB4H/bzJMG6y7QQS4HqOuVM1AEi1o4ljQo00TtSpK2ZItE2YqP85wbcHVJJkDwBaQBdXw2M7BoRse85wcxi4e6zw8MRse+3k5OmdxTuflPdZZPJ3PwxP7LJ6uzsuDc14e17hgDve8PF3zvPyxCnuXMcAQOEVJRlUytLAHk6VUj3xGAm7k0JY5/lPOHzZg0JBhI0aNmzBlkslJYxE0JSCHDF6XT/P2OjMo39GEzqTmv3oBflSkhcCD3xV0p5MwvpjsxTW9VNudueU05h4Owk4jky+e1gLGj8Ar5xGvziL/ibu/cfvn+rDa16N1cymWZKUtt0XTPbN9NvRHn5ZMwRx+P96whRtn89sEPwQ9/tw6u0xLMtLakZN5+L13PUrdDnw2I3hhBrxxxRkKCV36jb4XN317rSY63LlcDmzUW2h8LVoMtP36NaOvbaa9ZLLHaOyPX97ntFnL8VnPDxI/afjRpLHJu3hb3+L/dnjjf/Z56QsaXlfbfS6LZ/ObBx+/8iN6TTxY3nd0efd57Vt+e9M+LWi8ZiGuty2awL9neMsVL0u8hGjstXCxe8EdznXPHjjFSZmXfeOLjD2G+I65EkcLjUNli7+t0/OwvZcj2vEAWKPsHjx4wPTaVd66j1CVDffqW6FpCaMslVI0fkYBTd0OtM00D27RQI+eBnQarVvLqG9orJ6vXQVVpmqMrKREbQVTiWW5c1dTpCdyZJRUiymCNpb45TyxFgkz0xQTeHOLjAkWWWPcTCzLWcqStdWoNO+8au5sqcnKrM1cgWEkXo2T3ZgwuujVjUoRFi4jfFrOfxK6XlfiBeZ6f74Bc66rhDDNyU7GlLZFMAhizrDF7NDErNxyNJ/peszILZ5Pd/mMkDIp/MtmE2NCrwW/7nhf8Ol6H/DE42EWv7LPlRObH/3rpnCsF7q67xhqnZijGc4xaqkl1EHVtQ9r2JYaNs/GFhTX1pAVpWIrWppopu1IxghMwiI0mu9NhiRRMqzqw78ePQ/lzXBhQ0HDhLHkJE1ovyvHIXQJCBkxZs2OI3defP0mQKAw4SJFW2ytZKlkNsqRZ498hYrtV+0vtdROO6/BVTfc0eqhp9p0eq9Lt8Fa7EnRpwf8R/2wBKZk0zEiTeCAAdxk1aqeHfQR00U11XJPhRDSh6BrtoeOd5VyYnu6fCWSBam84068DpmeHSljgPXAeQv4wr3T+Hl5Y7AfYwMgW/Vjg9cDb7Kcb896f3PCJXA5dC5dhADn3x8FQV8WMF+2zMDt8GBLLG60XTz3Qt7+jrTRoOD9X3mZtgnwje/RSYMh7IgwUQjSJICADR6Qsnf8MC+OfPCVoaERC9xVelTlnsS/Jbh23pcPhTrDjW3euLJujmejbUOKptiU9e2I+Ep8TfGNxKZiC7FEbCceJ/YVT1k4bSWx+sPqT4lwaHj4gNtx5avS0cILHYsEc4HaKNbMG4pNxGaP3U3sAyV/xaIe73fHl/8f+nR5p+XlG/741kDNQPWAAPjj914f8dDXUa+9X89v7+ePpJ3UTnyVS36EwBOAl+k0BPpSQwH0xS+Gp6vPDw6yn8+/nGh+1SixZa1coUbltZ9VfoyxWVLo0MIgPBySB7aE147jjyPMAqvP+g6MqYHBmpyssCt5lxOEddxDf1Nj9iHg5fuwSYYCfLbhFnTM1X7XRla9JjfaQ123HqteVUDarYq0k7fkimWIkeybPoVFlwETI5gaydloLpzqMkGQYFNNMTmVQEsstcxy6X54YrvNtthlq1x5/lSqTLkSh9U54m8/NfpXk2bXXWuDG9q91uGFHn/Qmuf2AHxld7JTSSP6f/nCc/meh8d/1wWMHYB5LYCeCW74L8Bt3wG4ztPANSYArgGMY9Eksi2pZ2gMRLGtUsJGoUgBsBX1ZbPhzXUbYsr/0RNtQcRIdX7Q0ks2fD/HcEdRVECTRxzbtrY6/vviLR+XVgATGBMogatNOJOvUUSo0fPrWACzpa0SAlWPaKkTE7AH0T0F36qHZFvplgCphUlooAIsp2sYjgXdqx6qgGtr4rWhfKhWhXGNRQ+KsYeo15ZG24lzyNhsahXkFfTnDHqXFkFCqAoJRdWFKfJEyzuESitVkaW0UNYXTLND7cq4VZfYkunQly80u1ZmnU7T5nLblPmVwlqehgotLYRYPbXMV/n82rXCHORyfWlhnio6xDxTbBHLxXr7girMhYjyzMJtpKxYYmUK9lj5IpPPC5E+JNQbLDatbf3RPW1mEvlD95AN5qiKQuSqKmekeJlsF25Gx8J8Po1bZalRrrZr4kA2c936oUFm3jpSlizQMgtL3yJNLB1V3OSsTu/23VUotClCHIjJbN2qrNijqbpim6nq+cLYgp7TXcIEOomzIEcv0qURgobkoQrck9CSNmG8PAEjA6H7wQX3jr5PQNKwZy1RX0zMkiOKm9TlOthhgMaqmAM9YexypqTFMGOONKBynoLGqSkNaHMZVmmTVJREEpqPavw3Xmj8z3MIz6GmK6Ua/AKVvMEdpqrHdWGkRr/Hi4xb7v0KFfZPHJFkaRVrXJ8bwbEfj6loUB9lliysFEeUMoWMSI7XKCJDZVCKbZypQAlb7iDPlfhyRyg50e0I46oXyU/zymvRvYRFF9H9GV8w8yhdTWIJ3BGFkOL7qI6sB1W3lPT2s0BcTOvP+gizZAOqLlXcVdMQt8f6lNNAfSR5PMlta7qu0CzFn51Zdg755B62uY+Jdj/GJR4dr4G0OclxXcABF2rYpENjVMcsd8z51M5FiTlQTWlxSVNKJSO7jIB/jJijJV4UPcmhdscwmQevNWGIpVkCBnx1E71sBvtLMaKRj+zdbuYXoH5wyEjZwwxRqSAYZSrdVAfSMQdhcOzN8yIb0F8Tm+zvq5V9j1hdJNa6K+YpQ0AQ0jPUcqGm8RZwqaV1xQyqhZyzW+NeAKkSW5wLFploXpFJCrI6YVLXTebiOufHVt2sK64mIMmCn06kttEKZuTaXCN5QAV1cLzl87J9n/GalaT2BU4ghbuKAz+N9AQdO6MPF8BEy67KfMcSdIzaqoVl9m3CaR4y07Vr2cPekyQCWdukO61AC6vVi6r3LkVZOUGIOiGZqr52uA1pSosaGSJktlwJucSX6WIZzFzyrlRack7+d0alxUHqwMIsa4wDP/A+aJDqZn0jXzKYPU72qFcmyUaUUlTjZPTqhT2F2ygq+u1wW5AgRBUTHiIiiNrtl4hIOc7YZm3Tm14bKm2KMJt2opi5gVqnEHCmQueHK5xHhi6OL3IpFr7ZIcUZSrLry8duPFqp6MxAzaFd8e5VmsiKFvOFcoaKZCb5tcE5G1JPw0dqVrG7uWxfYid5pMcXcZTcPqH9tu8t+zQhyFAraL2MEnW0IAQDOpwXK/trqHeUU+5sGFh967ipxTf3669QCem3seTIrc+EkWWNq9bEMrLjSHLoKZQeBxMjcDzscm5vk3nYzjgXGmmLNlpzZpvTDChGC6RtehHgUOe9Nss94BjE6NSqBWuwOadl4hPSEA4yllvy11DQYPmmh8CApl0LHSN1xKaW0ZJ/wQFKBgrBgqGk18YRA4OqfK9btEDv5vcr9SUlYYCDRt4H+GPuQVdpetU9wB53b9LDOAinqpXrFe81eDp6AfqgPjIdwYzHpsH+mpl3gNGC2MRuEZs51jk40GRWoryEIloJBcq/YqJC+CoyXEualASwQtpwEtXbYIm00VHZ855OP5iB5jsRXeVQ6coXPNsXiKzEOiv38hFBzGF3bUgwLlQq+AtG8b0ocR6Lta1vYAQoxTWvMYqg384MPVpenkkM0ghKXyhWG7+fWsxQy/3qULPwWw3jZX9zuWr+F5LZvtSAIgYfWRJqkQ77ohp3I/0CRBc65FdaTC+0TNl1jHWiNqc43rWz9e/jq1nhvNFmmYbaTxh7OTuMqbUYNkK+imcOSNdzwh30zpchydKaDli0WJWmxmOOJOjIIfsmYpytOXmBLPL5Xrw3ru13zkkfHCnx0LBXGuHhoSJKmOqEjmmQIc7msX0Go2JFItyfTLMyw9crwUQZe1HoSudaO8qntrdneZ5OYNlUikXQjGWcbyvdTZIbZvTc76rdco5M6mglLI5HhoGGyjxKPdxdDvrcwQGvPzcZdPr67QF/Mji15CD5SclPS47ytT3jz5ruE3ouO2pKm2v3UA1VX1yiXIfjeYWPjh8NAVahrX84M1zR4DRvyF72Az6vplho8InMJCdGUANpher9nnJF3amVvW213yxrXkBi6fC5KbM7ysU0K3EtwWrKc3WoYJmgNAO/jIkSyRz2kaoSwB9UCyVH018lFjV3D3wHSnTGpE7rghj73l39Wu6z8++eksUnAZg/1YinZof44y6pUIps9CSW3k9flmsvIM+g7TiHn4bVsHCv8S1ER+MLbYiGTFWMC4NWuISaON15IdbrvHl4qiPof2yL+c5QMunh8NFD9LDMQN2ggY1LUqxkNITcUs1b7gYaqDbfbgVyHPhKAPexbkpHhqBNPyg8QLiMKhpwEc9Qdgd+FhsAxKu9oHy1wTXerzWjYzIQqWEY9eRaCx7Gyw+mWAygAbPf60jgU8ADJK1nU1DxfOGEM61lNXPXOv7zjn7A3cV7CFhQG1jHgIQCPDfRJ1r3WZJHtof9egtjne++2s9+de1q6Ldf8tznguNDrKvXHPuH4J1d8/pmOgdZtrS5ffWbxL2IfU7yo0uIIeofuhluGj4VLl8ZcccST0LO9d7P+Ddpz8pXoE5ZzM2RxrZV39Hm9a53RQ4eI0Y59Ea3dBPePMLzkXvtqv8kIUo7xpxzV0+KEqQdd5lvQMS1nl4vsFsqsKs/D5HXrtjuTzXbH151bwYy9BPAXbDmV2TJXltevuo5P24tO7T6Ptr856JQL6x8XpsHqipLWK163YP8FAkD9oHc+i1YIReQd/dDJfPJh/W1flhZxapC5DEsLbJ73POl6vk9p0EyL9WNjUb3qedksD8mXxMjRY1RmTHRPC+DIqxAbLp0zjmTEQCOK53dAqlQWh+ZHvZb3YYHqo8vQPtp6/1ZHwOAufzGM02Sb/58QwtgIHFltWr1/2bCimzjkl5N1LL8e9jQ/0VydeixjLcHxoNpE99nb2hFu/LaeG3+jyQpD0B8n5pf+6HMt52vyT2phF+ilgIOr5D+8MA7R8pRg6Z/TQDZf8OcPXH/m4GJge82JpqBVWrG3k9TdYMDpwfAHLAyb+u/K84+X8BDqAuTYdsdUZaN4ZzhUqlw9lXe2exx7ukOXRYeX9mI5+UNYSnVCfgSYpZe104CYT+4rIRenkr55tuplND5leLbSYMa8ZxzybITgSArJOv2Jus36iutVxo01ht6XbIuuJBEkDvhl3cUi2cHtbfhQJc3wbn4XWOp5YUTcvBZw4xiovYl5NxJwudfjpHiZ30EZmBlXgZWZgE30DTx8LMTEyd+2Zi4XaqbuPVfLbZhHQinuNzaNz+e8vW3cDHsnV9R3EcNV4vPO+dfd8Pgi/OotaHk2qf6SuvVZY3Vi/oGzYpYfF3fuGiKG50/4bSjgE//cp1jXUN8AJOjCXYG5tlij/ON3z9/RlmmGIwtshJ+UgzBy8HPfvscHJ68F4Hia0XKiivv/6yYbPO+FkJ+CP9Z+Ftwop7s+rX0aHBOI9eFwCq0HuzVyNGtd/rSnuwAmW/JaugbX2mA3Few5jY67QSszIv0g6DUopro+NsMkQdb9tftLVh3WaePufrTzYHi/TWH2tyxO3ZaVGMdqsLpvaP0PvDjeTlCRmoPpO22Zdr0Y61LB+Cj+pHvNQoOp86cQlf6by60WaSNDjQQDpwEp9pODV0JmZ9K+fYbaBRyefmM7pleY718ieAQ1ek36qMrDRqrUrDz+oGFKdLbD7Txgfnreyb2tL1oVlqcO0rSL1rapuvAOuOHvf+dbtdInup0ko132tOicZ6ilQJrYrFgjW3ksihgtQ8eP7459qL39+Sbwy+6l3rB6PxVheTR0bj3ruT0sckmRQsySZPKTqppxUa3J2W5A88KBkCbx/A3uboFW/U1G3qWpAeSKhhKyigjYyls3RGy62zEbMStpU5N/ZXPc9uOfsitOW8pXXCQXFDoeG0JZAmaxOPWQbidwStt0bUcRkueSnPtx2JgHeg0IZxYB1ahDcAqFP7aeda6Yc/3vRvLt/O5pjOZKtXpzAxT/u3ljd7W7zc3AKs8bnRWvgtP+ffwfODhZXJ0hO/6fmoGdz0E5quO1zp2YH27fPq2Unc6Uh+Of9e0sZNz/nPHnzsMsH5dvn0b8V2TG9d2rONs/nUPnfnNNsuzJukHnrs2B7vqQsyeIqefz8KRAFlSs1+O9+tnsYdQcZkR6f+3uiPSE3iHUC9jN/zobk0BzthXm5UnjrDCWd+GvIxgxaQtWysBK9sPIX0d9D6cQugILiIEFxM7DxIC379SJzob1OhDRt/thwv0EUnEdKt5wtkywTM4Wj46hBY3Q5AGXbw5OE7AMw/xNFnQW8jDl2mQvb5EuxyHyq1rIdboSF5uJIlSHI7GuU1DQwXtJWcOpUBbdtWRU/prP5zrcQiaR9NFJw7wG4gYNfL4dLIL14ll3+FvIw1C4GAxscTcvWDDQzzD97d6ptaIG99DY9ATtkqSZpoFAkF7NnEgXaBmnuplCxD5gSQC9vR+D0ZF1SWsXLVKrWh3yfSGBFDlZQMwPvtUjLGG9vQ4fpGsD6bRYak1LD7fQESrkZmoiCwhwOtXUrdfjdhH7Dfu4kilyRIa/MHJneJqLIpz0GXmNLAyz+11PDA5TYspaHpiLLc4V19m+aTZNCRqkqKXS+WohaYCca4xF31ZrcYsNYnpngkdyXPARt6Iv7Pnk1at5fQx7eZw+9RDbQ1RkJglbtjpsIVwDBqS7hktbZWjlqSFqCutMik0wwsbFY6/cirMFZciL6O1hwLYTuPT5jLL8/+UWzw1Ggu0GGSal+NeNbAyn55x8UZzqrDkIaFRjFlSq9GXjbm54qYC1IK8FL3cLAWynSNftWo2TddVWH10tIc9HdNUQ396HM/vsaRHFyKn6nkCQWs23vy7T/exhHBEvEnPHPKgV2gvYkAon9vX0bf1OvfnrLTq9iQqjO4CDe99ci+IjmdQ74HsefVcQlnu/vYMLZpYHpWtn9Y2vt9+CJlaBZfon2oqfj5zRPnfM6NRUoVGpR/YPnumoq364mtmU77QyMGcVpWh54zCXHGzBH1BKsOcac4G1BMDMl0L52p9IvquVGuLpzjchZabFy5V69tLKVpUsg4McOe4wO4J98JpIErubicXBJh8SRgWHaDb3/m++ebd5h2GBThgZZ4DVmanUxKtZscwcA00P5FnL74z4E9HUWS2oi4Wq+o65qp0d6aLlF1J7KxBOney5qe5z8r63DS8JCGmAPNy7v8fWZyZVBKHKmOvAlvGnQGOHig02WVudS5O937aGqJn6rSWX2DPUHG7DHWlsAi13C4vdvSnDk4MA2twetYlkHqafO0lig71qVHI6pE5sqPr15HvHR8hl9nT3tee+sRt+wD39LSDd9iAkO+S9cOFdb8HUDRwjJxwBXjslJ2Hy2qdM6eCd6bXMfmljTmoGAqBtmN+X7f/0S4FL79jgVYmG0Lyy91JIyH54iwJvy4dncDGZblN7O32b++SZRf23EwFc/TKwrnrvCrNTY7sVLlac1oc4Nime+5anyJ//rqobmx8TN7YkF/c215bPZWOzcNC5fDc+haFtKNOTAGBfG4fvG/cbi4IH4fEbMfQA7rn0Xb+fwz3NAD3rZG72Kx3qEeajeozBy5wTzu5j+tf1urzRjlnysPWquLwBEU8sibPNJcV/Vec1/EAY4O2QhBaFN/Co4j3HDgg3pNJiW8pCrYAH3bNcW982xUohNz3zIR7ZkLuBwi/7bqxa44Lel0h3JX6z3fnJP7jPejj1RP/r6dI9/lq7ee7hXH/ePXv8elL+Mczr/7zFcxVeLbtT1dCyODecZeUYGdm8ETIsCuu7U+QdLkGNAzxzY3PD9NJ7SEIbigC3R5Fb37+cESimyt9PPoXhEpoCoZlBsNQTYepY38BY+eB4wEFbAcMfhfZh7Nrjg8skht57/8m+77ruvcFK98IbkllFDkMtRVo9Hsjg7ZkjmNag5y9tpSOA3td6yqwMq9aze3XgqFX8pI1RVnJ1VeyoSpTlbApHiOj0TBlTTBhFYgrrU/zP1jA9ncJ2tr1oqH8x35V2Q9369UM9REmQ7VtT3rt47cPJ5lYtTru57VbmxXI1TnV/9vqOwbzjFmYMSEXdqGxXCpqFCPP5GYnnmoUA8YLYKNPBzb68Ssdt+8DrMwKeDkeGmtQzwTHX807ZdDWpN21Km9/6M5aqHn3URW44LjEB4EGjAFSvKe/JQAFZYfYBIEFz+WUZU3CowflLSUX0xWmbdLp3TvEdZX5mRWEI9WbKC6Tm+CRaYzoTE+GnYds3PbgggMJk4d06jp9mN9A174uAP/4GqLtIqQNkuUP74BCOjB+M9iBS/y4Yj+Yak1fZLW2UmS9plMlSX2zjlTj+vGYe1jprOvl/pRvvmUnzHV+tvgOAeicTV/OVjB+/knN/PLC2NhXFyqYP/2kKq1mTWMF3c1k+6UGskP37wWkYwt5y/JFsn0GBD9t9NDiP3z9OLn29xHfgb6G79xp7IL6aBWKlFxcGUdhqpEINeNinfLW40Kd7n6hfLGUeqSnfa3WiEpzOPMXUDl3fMipO7e5dNUKzRA2RjG5bTB6KZFKUfWiipRjytS6hORiIg5WUBZHJdRFMQQW2EuW8tpzz3NqjbeL8i+INXVnin0duI76pehjXFXtyqeFoOzg8eDrtrLviN4yC4eSce3BDIDdfwFYmQHdufaRsOL85uLLVknEXHUMPq2JTj7K5dG721K4qOZ95865pn7YNi6NOG/71BhGFE4na/XoC5LWqnfvqoDOOWMe0TOYvv3hDVxYi/mORFt5I6fy3Hb5gjvPWC0vOalL/WeWV1nEajhIrFqv1LxtM1Z89EHfbUprZdO7MtIpnc2paUg5JJUTpkhiUbtaOeB2iMDH4Z/xq+dCmL6g3Ln7M3HVopKLH6rNpznaSnZr5xUlpecfCHW1D4SK8yWKqnnRbluKY+0a4hBXWbP4mfjYyZxWGElOptM17VgOtx1L19DJRHk7LGeZrExAF+PxiAJVHJWmikMU4PHI4ooEkOasvZFTObtdccUt21irKBnVsf6d46mLWIYwUtVTjeZtq7Hyk4/0PRbp4BKy+0S608ObuPBm8x1JwTKy9HAqJ1wBT6F1tnA4aS0sehcnndJpTAXdftNZyfzppwrmF+qXF1SmkrHeHTeRtiw1kraYzVRZufgp5YEPQ71DLr/6zlWTqstUZfIVnwmDj6ZxOw/kd2sAV671PuLFoSK6ArzpJ/I796dxg4/mflKWKVBlKrsCqUivDKinlluqzTh3cfYieKBTdgVQEV6cI96aDHlVd/7RA8QnVfiZgsdXBX78z7HsjFKtJ9Qrg4rsClRmqkCmQPFJbl63Akf3+0RiZ8HFWQAQzkefSkouy7LJzU1KVtLrkdHf9xMhGG46Fco8cJASBY0QpBZEI0I/hr2AjJF5mh7sMXYOu/sks1A6nJLaxkZGyFhZfSGv0xE4OSoZVVgZT2OPYqvr8SvlM52IpZSCe3FY0ksiuPcWXPv5Plj/OfVrKIkUDdtDoUQU7YHVvC0+e1SwlpqjW9wCERFx+ekJNKtbGtw7c1KQwUl72apUNIxfEI2MlYRhcq1oy5srFWfWOIqaZb7oXIlSdIoX8xsJ65fL3pL6gP8Guvu3GNyP5TCRITw6oWCCwmiEis3drKoVZ2dVrwhEZ0fD9hIxfnks3E6E6qCuXeAFdxTOl+FwqjOEfik9FtehgzgVHmSeO6N5XrMGMt1YFwvCIrZW5cfiiujE/jM4lRyXJBh5V7emfgI+uAEbZEvvR8B6R0cvULmdecvOyxe0+sKD/PmtXFKS8V2q8quvylJeP1VSv/iGqH7yMKru8Ucir55812fI8waJHKL04SQ32w5u5RXrztemvW/Wi9cXVGW8KtSYPWPgaBycDUsm5ng9GlXTvhif/z89O701b/FWlvfFy1nea9d3CxYoPV5lAXdCjea2wJPuJ7BZCmJUv6I8Vq+ISqXJGPFNDE74cFE2uOUkMHc7ocyRH467H+O4H4vbfnxGn47Q1tF97t1pbt3gg7N6I3NkKv1jnQ6ajUxucNUVz7mjk5wuz/lkdKqUqobLr2pK1rXVrMFVdXnZdbV8vVpLWlzX+P7slFpx64Gywuak3A4vVd67h65Sr5x7SsffNM0q7j0A+9Du3tZ/mODuwK7o88CuY+9hwUrH5KlJ+64P45PjYOu7t6XhHz0ytZgAzGJEAKoSVUA3StzOamcy21lsZluIsthtzCibxWxfHthbHi+PakyN6kXDox4e7+hYW+4addV1fdY5lyJ33a3YBYIcgq5ytxT80qrcUNs/bNjIAHLrynr40BjM2GhiN72+/oCR7snu/Ksg2Ww7H3L1IUPkmU/59VIOPtw3GUzQ6vP+hABKzs3Jm1FHB28MAsz5E9OT0wA2JI2shcpK2bCYyCq5TBbwhBwcgf6pySkzPZpIjI4iEqKjCYQoSBOjfl3IBCgQMTehG+XgAXLi7ESsBdFfmPsCf53sB+MXN1XQjunhOJwynoIm/hqUgGanntykoh/TwXGEChgBzv0kKAZPBVwQfS7W6fg+5Glgcg2Bp44CwUNKn+2X39Ktz332i9ObX8Blo0Mcdyq40qP95mC0Cc/yyi1xHBvSmpUMsyMEqP/sz8QqfiQaWu7FND8i18t+4TNTZU1pxBPMzZgtvJ1W/CgfqoYwyS43pw0OppnLyweeeLnlSg3sMLukSXVLobilUhk7p1LeFswF/stMzr81W/594L7NjxgQhYuJhdIoIYHX2IMehWFhJW6Fa+D/43LZteuysrzTrJLurbyzjsl1mQxsGRpTlozFKOYJxDLkXEfcWQdefq+JlVd2XS67Nl4/6KpYX1e4Dg4ODF71BnWjgZmKZ+mjo+nPKiqMjV2vQi4QcDhy4eud2SP6UX3Wlzsj3DPdpe5Z7u1fZH1hcY0xxgBeiPiMHnZ6DycjvbcnLYPTnZbW+6TTerrfJcci6eHh9EhIc+gRchgR1YFE6gbCCAfFeqYhhlJMyxQKTuyn25Jts+2/8tqMTMWnpAqRsUNBPvgSTlsI4XCZuzgBUZx2wCSzq95Ew+pwuZAoRph4gb49w/4ayU4ETYjhxYFv6ysXJcK16lrh1cX8ysqF/NyrtdUXZiJ1C11MgtSQyZG1+WQ6baVrKeSIdfUAWZ+7D7tv/rkyiBngzwgKQPoHIYDTL8++G3TvrbI+IU2mFre0a50G+4hMFgbDSQdJzP3CzYzBV8riJ/X6YvMr1eDCln9TYfH3QBBxoGQ4ObvRlTcU4p6WJy7MKKaQo8OTMZE7PEZ/5QkgpXHx0VIBHmUZEABFFJNb7p00jZ4bDu3qDvblpQuFPBEz+XA4DhsZ4DGWFMQVRhTHJMYUCjFJVkG9cUSv1AhuVsMMbqvxNdsdSYWHeKOu3PYa/Ym+O56WFOyFfvc38Ik6vX+m1/ZlVc/DCmCTU1NBd/j1z0+8ozISUBhWQpSp5KKhrXuuLs/XGX4YL0inxvYU2lzYBTxHy7MHj3DzNqHO7hRFJJOy4w+Fi+M5hAoCMScu7AATikRnR3mOA1SaqCeWm9UWR85NQgrSaPbWYofiLCKKkz8SB9pgVubJJPCfa1Bv27PffO/uyNPu7pFnd+4OrffoCbjW+gZcO4GA6zAYcC1gd87+/cMn7VY7h0bUQCxxCpoawzh4CBd5KOLX8OMFA2qZ6lhtRqAPhV2WkimS26PrQYstvfYgKQU3mkfxCYshQw9CMEgiQ8OIRiZA9teF70sNjOiLo6ZXRxKYJYmx/Gg0NuONPdOOJiTlnKoFaepqxAHRKuJ2xpaH+n/Uo6Gk7v2gxp5YHoXK2Hc8HBm6L5aMj09gMhDb5oqbfY4ob9ajdl20eY3eGUhQoJBKIomg0mFAi+3BxN05lMT+6i72alc6m6CMJQnsYYOfJIVH4jPV6i0BcdEwtAyBKiMrRk8aaxIZzMQ4MhMWBAs4jRalZAFNSt+Wlm3QJtYgqLblNMYQhPDwvXT0kct2AwH8uERMljqaSqmEYrIS4hE5GrvuwCOh9Ag4SdgYk6ZG4uIhUCoyPpGChEKS41EiCDImIiIJGg2FQSMi4DFAYUdUxhLz7JOGnsIiIRGE6H1FdHtkbmwCuhSJKifRSTWNyWyLqtUefCK8v66HvXY0nXl0f1LoXoQfksFDwmgpCfFEJiBog6uC6c+Ue5WgZ70usA7oHmsdtVstq/hVUNeRGnQLubAP3pGox+8pRXga401h+R3YUtIvIJYUWRQ3scsAK8Xtgek79iUhFvbeYpUSfsGVga/tDnQdQCVA4I2+Pqa+vrNHbajxSII9s4mZNTR4A41EQxhqaFxeFS3JMMErs4p+a9QQ4vMQJHisiISHieAkREJeEuId6eNbTYPtnbhNGKKN7eu6jbZ31gKBq/yH1YiMZ+KhT9dbQltAsM43EO3+Huu8q9pTY8EmlVL2Jnm0JXt4HMNVWGTQikGK0X1/IpOZH/vVFFXnRa300LbSbEOIiYSE2tIcuxslnOQcGocmMD8mK6wbAiaoQlo4vGrdznE/8t7dHVIATHucK1618vHy8TnmeXKshgJMNVRuJ5cDFxCYNxRwaDk0TrJkpZ7mqP1QYiKhXelWQ2NQTV51UYTCFz4soxEoYIBQF6Uq8Zva4Q6sp3iKuyEAWWUtK5aOl9esZWt7RrWlKeQ9GBtDV3NNeQ8PlL4/UX18fKLt7a2bOuZQwMmx8k2JctCPRSfrDs8f62rCovC1oumXTR7g+LDyQFCNVyGCdzghXT4E7lbhTPCVesEpWMqHdmJEmQHKyLn2Hl6fw2gMjEaPzf5F1Xk12X8bdE0nWqiLySW0SCv/+2YyPDPlcDHg+skJ795PWpNbnfO30hFCUMijb6U1lIBIK9exKFQ4IGQb8kWhnt03Bk6lrpHJqPCIZGQkhDoR4eWIg+2lFufYX9mf+mhvN/v7aeDsMoYtQ6CL0c6UhjQ2WcFAKhcrnMrD1odAsNjDQPgvPsnAhf+DIcgwetXFqDAmkPZAbfGToG9YpIieDgw8FU3z+jQzLCXLMo1AZRVSy8GhTy+1hLY86DY631lzBpGb/wT6MqExU7235/6ucqoa7pfIXHW+Y3QW4qX5Wk/6loNgnXULuBFSftjpMs5uVhnJxai8VAFPXiZ8ptCovFhOPRg8d9i4l6tV9EQu4rskzl2bvCf+6e8+hO9rmVuXLF93kFu7oxZh+2ubFsL+n5xngwuvrvb7J2NED+h/cK69aJVGqrU4mz/Iv8b+V5bvi9wFAU5pxSVX3OIiN2fDTbVwbyNPf/VHUNd4ate/WY3Tnm7/d9BDf6cB3bpmC4Ruml4i8KAYwq+BQQ8XeGgaJhCjLmRH4/m7XivjzR3CvZ6wloQ0iqYGDcWmr9yo4i7uT6pbyMV6xk0htSZxtAvoDlrs5kB5dOTVyykevJzn5kNxEzPuPRK45ZjFmmOu6cea0WUp7nmhWdwXxc3fXqPEy4ZMfIkq8V0NB+W3TDCsfoOuF9NcvAUEKgAnEFBriasuDYQrwAcgxYObxgjubRVrsudvzvBwhaD8szQ0NWh0GPbVz180M/2Dsb7rxD+mi2HSqbAvvFlgE8Y/EmmjVEVCJdFElSxOA9FqMWi1eDMMrKXiFgOsScjfHCgPlr/zTz/MjwxsNtDJF3frvl57GwWGmwPJunnM8+Cm8d1oK7Dh+CWpqyEasnpTl8hakaxx2zQ3ws6BqyKbGHVKhnrZGC6/i/cgV3LsFy9A02v7x572l59XjqIPN1Nyf9ZG82So9/lldlrujjyt6ZwX3TTqZM8Y7EO+HijKQzeVKIVdWByLZ80uUjwdLnrhpmJNL/VM63e9raKaK+xKCEFxp+V5sh+Ij/vd2XtUNVZJ9a2J8nUtOj1Das0/FRS3XPp087HXO4pN3HuE1jXHnJ5B/z+s7jLE3aFgoHau0vrlzieQu1A/Byp1MjeB0/trihhJjlWXgwsDJef3h535+e7Iiw25ZS9oNnwTatYY3qVXk/3mDG+HLa/Qg2Dlxb9euKnErV4NbkPZR9RVrPM47i8SLO/yyyFE2VM8mXJnAPbHVjHUQh75w25u+cNuHvEpBra6qzA+m31sWzpV1W7LC0JS/l1IMcD0OjW/jqotXe3gFkVo7AxeP6JWPZiB9yttCco0V2v3jDnqPULR1dH+Sux+iz+tJsU0bxrN88E0q7JBiJVuwiPvzh4pg+/gLoNzr8rF2GabaeuezBhxOBNdx81Z5s4Oc45F5prL49Kj8X+GwmTNP/EuLE5fjpHNkf2Laxe1dEZfwiXW7pHZlDuDxwOv50GPG4L/HSxwJ9xENofCItr41gw6RVz2ePfVGsxSr4+c9svisn/x9H9GBuTYgEzJ+nIqtwLcS6XvQJV2tFWyY6xKP0Ytw+S2QTKlWLK+VWC2awPCbIoYBCIIwZgq0z7b4HTgj8J9hDVgoUTWqUQ9fx67lk31uCwGMJZUS5JiKZamTKU9vSO2JLTDB1g5W9lVORX9aT+rwF2HQbInzjs0GbGVAvphr/g7L1ZhbhC+QGu2C+tuPMMHrBvW1TURUroU1Y08C5BxUEwm6fJFpxn6VA7bIJnyeZIlX7xXFoyvtXKrsL2msn1Wafutyg5YtR20GvtLa7eyr3woXcSV/lGxnwFWpdq48V774eTbXz1xVEczWnppQUPffOBOC1izxlbRcJ8HPOQRj3nCU57xnDZe5Imglz47Ri+23QejA0he17bb/9902x+RR9OPffa87//H3/n/+0OXV/9Rdiz9mOa3w//KH/Lr4sfwQB0/j+Hzf5b/07N8+x3Uf4DbnuZjCsDHnBLwILCeeVIUSXT/NEp/hTHyWSTfUS+0zD3u6a0txnRjapR5e6j8nrfy1mfIx2uWsgj9ajCfrqtTUoQxkfMG+Y5avVeIoiFdo8CMCCdgoqe0o14ZL4GWlV953sAFvcvrjJujjIPnwEjsIadVxz//bqdgCSfw9QOld1SdUfZdV5D2xu+k8dSw9f7JGL039+yTCJMaqRfodNZc9acgiJDrfUA/J40IYx7an0jamDcIA/IdRXdgRAhHSulb7b9aAb7ISs9ni0sjP/3FXrZLR302lj+rF0khicKYbc6i+2dDDGYBMEbjygWvWPvpW4PFUrQwBOTTux51lcUjQGxoKVjkRkFMsIdmngfzs00zwpPsPrTI83lr30VABIN5CWYCetd9LVW09bt7r0WFnLRS3VFTs8xW3jHz4ExAPl+JYSVgqc4F7Ra8P9ySa71XoL0BC37FhePMCjkB1VCv1XpQwEk+pckEvX+3HE6C8YTdYvg9GLda/YcW9KzZCOiQjyplPAI++tdh3Beaoc9ej8w7KtVuCRtRNrnH50tMiriqCsynnRpTrUBIjT+SRJcMZW1deWp/TQZYyVni6bvV6gexAfmO0lfDp3ELEu133nkzZdNoPQdu1LMJ8Rk1j9ZKnMq1THXHTM0oZfw6yuowns5ECc52HzzlOyo6ExjezShdeUfTMRY9OYBq52m+k61XPzmtju7snzVjLMvzriJfuKcguRAE9v+1Xrq4YWMI6iSAiHwvMBB2exFrXT/65GIjlirA9vdgy3cU2TW/COa71meKjp9KeIZj33vN6rkMKOal5qcy+CCU8GJrOOQvJdyldXSX8oynsqnIJ1RxXHze4hddPnz563H8HZAsZPUCSSA3tIPh411kJIBvbSjQwwfjp/TfcNII2drGHVBn081XI+eVNLM1TEg8MQ8aORdtMmqxSzlDXU07E8aJrko+4d74U5dkYr5A4IazFNd2urYDMknenY0zdKewrKDBkDj0QQ2HM93UIhs6Yz5wdRQcyQajQwYzaa45PsZO8yuN2k7MH4rH/lm0J7pheK6a656dVcP4jC0BtkMHSGED2IHS/g7worX8bD/Bdg3l6Nzemy9g6wPgb/0BfsOuOiFaZ/m6m81KHnxHdU6/SzdHuNusrIHuiZ+XdlCGspVMIyvP+D69TYh29ITKbiXv5pZ1V8sjvunGi6Vc7AkTIkDd/VF3Vsyygs+w94zoqOGIp5urhueOc0PrKDgVG0xrBlMx17T6SKf5ldvajuIfasb+eXBPNHucWFfXczOGyVUzlyux2sRjM1hBUcq660vH8TUt2gvLKLh3aQUuYfH+7Mx4J2MGjcpLIp2/jdKjsm3KR+f53daR2pmXwg8Q3vEMsL9umeFGEEsjymvXD/3aRYpAHyfIcBltNc8C4rcFeeeT2rGtNofV78EOHP+t+5zWwQXdKyq/Y/qT66+I9VZ6rKER/Ri5pdzqyYUZ4c/LUxUkehWBHXquBNAPSkBMWfB8JhjWy1pU2p+NMoSHR6xnG4L1+j81CAiPtSngr9+Z8WIj7t9ZFAsAf/LndmVZde9/8kWcP8TaePpdFYjDfwB1bvz7Rvm/yDrg49eQsTP8w86zwfqk3L9Erl47bT/qyHPyyTepH1nrEZrfbf9BPv0n6vYRpBz1qKUXV4PjI6B/ioT7LF3txW4edWTpi1wxHtbD5knqTS4/Yb/j9qTGkAVB3Yz4kU4JteyJ/gt1cA/r6MBOO5XP45/IfToL5M/w0oiMXKl2W59RRTpaKX32AE7d1/iN4Xpn5dTFVJ2G/CATqZTjODyytRrOoDe9Qtuw0erkrjOWiva5431hnJN1WYDqYa2FR79vZb15OmjL1/8rVx9YOS1BJXOz1hEJd/od9RjI0J2mtQzA2ftncbqW51N75BXE/kxgYO2xYvoaiuW2m9o12crrx3Z0VgtZrP8kbib3zQP5TLJkfVC2fpS190lfK2Wv38hXfcvWz+S1sMPsNryGi1AEGVAPxXDKKoH+41irZCxh7jEMyfHQ0p5kTNbCHdZsKhqhAR6AetJVzebFJw8E5gg3hh3gPay7WjmIKndYO4XG4sfXnsES6IhtmCLK93jDtZCcR2lvJ9k3pY+PuIy/WRNHl+qXdB5NuQA4A/NjAb2A3ESlxIRa57kp26qMcaX33e63xc/G6CDJjqp8fEWkIS4+F6azWGIha7LYWMjGOwqfoQOudm2F28+LmvZNq33WBNuPC10WkLJDXN1hYi+K2vWx0DlWzhxu8nxtdseKmBWWLLPE1ZR8FFk+G0qe7a2o4Ze8bTN77DZj/Gj53Aqx01fU+It0OsDscVPwtILZtTA9ZOzKpXOXbX1tq2N+PZH9fI/3d3jcMuOR3/RyhNjrlc5RWC0npGgtcNlmi1/20DFbPRjLOA1b5cAyIMCv3eOf9IV8wMDRnUDvAXD6yjRPnUvzghQKjjIgA3shqNRa/BzAz0jqUfdlrfvO0v2a4cpODaAbAR8CXgfcA3gN8EXAr63jXNaistzWqnoB+JM2wfrh+p0zbClWf8zZLLR8kcCvzVXcIBg7ROKIxIA+ik1nrq3q2yqTDeBzC5XZiJN4NsFPOJviqmM2zVTTbAZP+ZyZSenADwcUEIF3a5ztzYTFbB8sIu6/lzh8Ujvp4FmSrLVUommklkqwynJjuUsmNeegJ2aegLti89YoFyd8bF1lhZWktZTJ1vM1JpM0xkkUXx4kkoZNT7n+SZdklmKFafbxOClGCxXnMVWCpbQFMqy3ytvET1yQrn0ca7wVTulx82RNJ16W5zLeidpG/L53DDXPrPGr40e/r97taZOXepQhZelBzI2GMj1/Muwl7j0XMuR5O8lqcZZrDpOkhqol+XaymEPYDpErT2bLuFgelzZGs85cX73XYhXxnCNiud7lq+X5rrEDiI1ljjqi2b+W3xjEgJK3wbZ+N9iJ9Yt9bHDQIk4TTRzk3odkFhw53YnEGMU/w9ntDN1x062M7kAyazSXe5AYY+5LYrg+5owVf3OSL7PiZoVj/nDfXfeSZJ3NPUrG7XPAJxw3LmfuPG5QYnjyP8qrsbw98sBDK4u4UclJPo03fPk/qon5G98kfj46HzxEyFCh/VZwWFOsskZCyVaHCy/RWpURIgqMpEuQJEOCI5tqvXWSpUSJGi26aabHiGlGKaWa6TFZLKmk0u4pMGwW1rllmvNfMRgh/CcyV3qChOUKlSnLfnIZNpSXKHH5/jEviTDzK6jQgoqS2im84kpE2JQsuY0Usu9qYizkgyL5PlHvscg5n+5aYormP9xnH+jYosjW9BkwZETE+PvxE2Zt/38dCiMfa9P+S6W1Tsd0fZX+2b2/a1o7aYzpp03JZH3oD5hWL7jo0m+YfvHYaAdIVOHimcBfjCWsO2fRFUuWrVjFdJHQYu9MJFDvhO2tdaWrXXPKaRwMaiddd63r3aBH32Hm/cvCVQ0a/e0QS1bE+L7odsaflv53dunNO6z8ZXanu6oFmES3e3LtkmezvVSZu2+HbT3pYY9caKMnPe1Zz2vrRS97VfvdVfC/5P2fu9PWU2999TfQ1wb16TeA5XeT7fbEU8+88LJvfe9HP/uFaqi/FyDJiqrphmnZjuv5eIKmlraOrp4+BBNJITcoVBqdwWSxOVwegvIFQpFYghlQwl4GPJ3fzieUy5a0Ie7n2mhJTmXtSE92TsafjyUs4dOERxNTsF0tmC8POy1s7qk4TZYSJriQvxFhkW0PiyVavGXc1mv49jAjGymsC2aZhB9jfuRtKWXWdhsl2pV8glIrsfeK4MfDgvj0sPe3xWKXHqb3TfLk3cfhqL/WwslKSsY9XMpYvXQAC0Go3AlWafj2cOQsndjjhgg39zZ9LQVSfDe7Wdvl4wGrX6s1QdArCGUUHsrOJi4IuVHDM+fCWNuijyGdJTFW7GEiRENAtnWGCMehbSiopa0QGccV+DVV9YeDMNaVJB2dSYgqxWoQcEs+yP6SdX4AFU17++ktzkAGijDNsaqyFOHNqVAd3yAgaXCQCkaR54yCvFQQ9hPnpNJ8liRWhAMmU1Z2aRfKrvZK6lg2hEMz9DGoO1gIoRoMNIb9famRFL0L3vBjBTxdiiYrDRm+a2tYU3QFV0gd/+V1IvU/uGqsZLg3rGQnxD+18BNMhuTZlVyV+fjhfMoryFu3ho5LP3jc2uflY1/K27XKINDxLVFTGpeAjQiECLvrif3y8cuNPuKlboyUXdFLVJuzbmKuD1hccD9Rh/PA6vK1zKsvm0bhWiHbFF1gNpyc3/xWNgkuWyudT0T0nMPsn+RW8To66TcxdblaNE/4N5H7eqWn8+1Ykb6bM/NYXgVX+kEmlCY3aUXGrMpO/uvEtL2Kl1B00idTXhdB15nOicYDhdEx6DwRMnzVWlkHmATGklh7dFBdQ2s79V7fpTV1+9U1tIt0qVx0RlzQeCF4o13F0cNUeo/s332B8+KauFtKee8tsgaulLSU0yKjpZxWK1ouaE1N6xparego+N3zV3VAxBRP25X783LHFXKWc/AsG93y/FbwAzkEUADPslEOBRxBJAfAlQqufEkOoJxQAGKoB+CB9oXegTRyMU8gApYOAIXWpYMsASiAo9BQAABAEABQAAMAAApADAAeAPQOpJEAjYAEscSG0cyy2RgKluc5RnjWndIyhy31uJcwo5EgpZhKphBm2WV6ckPIHMAyq5KodfKdUlLryJR2dO4LeSNmZGN4kGWVe99idvjLTeLyPsRkGVRlkAc/By3qPi9+5U2IizpfahpQ0YCafg4dV08XTV7diJ7MBk69WKVXcDeEZ4q6Co6zp1rdaD0/nh3+u7b2qLE5tBRrSShBP2YrT53309m5XXO6xS4Gzwcbtu4Di6PDfGij1n1i2p8cIhrKPbInIat6DeILA+eFmBs95wPbXgG9npuNOiDMOlf+nsZQ7WdJ559R9o5qd1d5XpFEfsq6l4mOZ5ey8UsZ3vqc//d/XUIz) 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
|
+
`;
|
|
4123
4691
|
|
|
4124
4692
|
// src/render/html/html-renderer.ts
|
|
4125
|
-
var
|
|
4693
|
+
var GROUPS2 = [
|
|
4126
4694
|
{ id: "A", title: "Activity & Cadence" },
|
|
4127
4695
|
{ id: "B", title: "Contribution & Ownership" },
|
|
4128
4696
|
{ id: "C", title: "Commit Message Quality" },
|
|
@@ -4134,30 +4702,31 @@ var HTML_DEGRADED_BANNER = "\u26A0 Narrative unavailable \u2014 showing raw anal
|
|
|
4134
4702
|
var HTML_METRICS_ONLY_NOTE = "Metrics-only run \u2014 no AI narrative requested";
|
|
4135
4703
|
function renderHtml(report) {
|
|
4136
4704
|
const route = classifyReport(report);
|
|
4137
|
-
const
|
|
4138
|
-
|
|
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);
|
|
4139
4708
|
}
|
|
4140
|
-
function document(body) {
|
|
4709
|
+
function document(body, provenance) {
|
|
4141
4710
|
return `<!doctype html>
|
|
4142
4711
|
<html lang="en">
|
|
4143
4712
|
<head>
|
|
4144
4713
|
<meta charset="utf-8">
|
|
4145
4714
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
4146
4715
|
<title>commit-whisper report</title>
|
|
4147
|
-
<style>${STYLE}</style>
|
|
4716
|
+
<style>${INTER_FONT_CSS}${STYLE}</style>
|
|
4148
4717
|
</head>
|
|
4149
4718
|
<body>
|
|
4150
4719
|
<a class="skip-link" href="#main">Skip to content</a>
|
|
4151
4720
|
${body}
|
|
4152
|
-
${footer()}
|
|
4721
|
+
${footer(provenance)}
|
|
4153
4722
|
<script>${DISCLOSURE_SCRIPT}</script>
|
|
4154
4723
|
</body>
|
|
4155
4724
|
</html>`;
|
|
4156
4725
|
}
|
|
4157
|
-
function renderShowpiece2(report) {
|
|
4726
|
+
function renderShowpiece2(report, provenance) {
|
|
4158
4727
|
const { summary, explanation, coaching, explanations, confidence } = report.narrative;
|
|
4159
4728
|
return [
|
|
4160
|
-
|
|
4729
|
+
masthead2(confidence, provenance),
|
|
4161
4730
|
summaryBand(summary),
|
|
4162
4731
|
toc(true, report.analysis),
|
|
4163
4732
|
explanationBand(explanation),
|
|
@@ -4165,17 +4734,63 @@ function renderShowpiece2(report) {
|
|
|
4165
4734
|
metricGroups(report.analysis, explanations)
|
|
4166
4735
|
].join("\n");
|
|
4167
4736
|
}
|
|
4168
|
-
function renderSubstrate2(analysis, framing) {
|
|
4169
|
-
return [
|
|
4170
|
-
}
|
|
4171
|
-
function
|
|
4172
|
-
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 !== "");
|
|
4173
4748
|
return `<header class="masthead">
|
|
4174
|
-
|
|
4175
|
-
<p class="tagline">Deterministic git-history analysis with a grounded AI narrative.</p>
|
|
4176
|
-
${band}
|
|
4749
|
+
${parts.join("\n")}
|
|
4177
4750
|
</header>`;
|
|
4178
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
|
+
}
|
|
4179
4794
|
function confidenceBand2(confidence) {
|
|
4180
4795
|
const level = escapeHtml(confidence.level);
|
|
4181
4796
|
const escalation = confidence.escalation === void 0 ? "" : `<p class="confidence-escalation" role="alert">\u26A0 ${escapeHtml(confidence.escalation)}</p>`;
|
|
@@ -4188,7 +4803,7 @@ function substrateBanner(framing) {
|
|
|
4188
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>`;
|
|
4189
4804
|
}
|
|
4190
4805
|
function presentGroups(analysis) {
|
|
4191
|
-
return
|
|
4806
|
+
return GROUPS2.filter((group) => analysis.metrics.some((metric) => metric.group === group.id));
|
|
4192
4807
|
}
|
|
4193
4808
|
function toc(narrated, analysis) {
|
|
4194
4809
|
const narrativeLinks = narrated ? [
|
|
@@ -4208,7 +4823,7 @@ ${groupLinks}
|
|
|
4208
4823
|
function summaryBand(summary) {
|
|
4209
4824
|
const findings = summary.keyFindings.map((finding) => `<li>${escapeHtml(finding)}</li>`).join("\n");
|
|
4210
4825
|
return `<section id="summary" class="band" aria-labelledby="summary-h">
|
|
4211
|
-
<h2 id="summary-h">Summary</h2>
|
|
4826
|
+
<h2 id="summary-h"><span class="kicker">TL;DR</span> Summary</h2>
|
|
4212
4827
|
<p class="headline">${escapeHtml(summary.headline)}</p>
|
|
4213
4828
|
<p>${escapeHtml(summary.overview)}</p>
|
|
4214
4829
|
${findings === "" ? "" : `<ul class="key-findings">
|
|
@@ -4219,7 +4834,7 @@ ${findings}
|
|
|
4219
4834
|
function explanationBand(explanation) {
|
|
4220
4835
|
const paragraphs = explanation.paragraphs.map((p) => `<p>${escapeHtml(p)}</p>`).join("\n");
|
|
4221
4836
|
return `<section id="explanation" class="band" aria-labelledby="explanation-h">
|
|
4222
|
-
<h2 id="explanation-h">Explanation</h2>
|
|
4837
|
+
<h2 id="explanation-h"><span class="kicker">What the metrics show</span> Explanation</h2>
|
|
4223
4838
|
${paragraphs}
|
|
4224
4839
|
</section>`;
|
|
4225
4840
|
}
|
|
@@ -4234,7 +4849,7 @@ ${steps}
|
|
|
4234
4849
|
</article>`;
|
|
4235
4850
|
}).join("\n");
|
|
4236
4851
|
return `<section id="coaching" class="band" aria-labelledby="coaching-h">
|
|
4237
|
-
<h2 id="coaching-h">Coaching</h2>
|
|
4852
|
+
<h2 id="coaching-h"><span class="kicker">Improvement plan</span> Coaching</h2>
|
|
4238
4853
|
<p class="coaching-intro">${escapeHtml(coaching.introduction)}</p>
|
|
4239
4854
|
${chapters}
|
|
4240
4855
|
<p class="coaching-closing">${escapeHtml(coaching.closingSummary)}</p>
|
|
@@ -4243,28 +4858,32 @@ ${chapters}
|
|
|
4243
4858
|
function metricGroups(analysis, explanations) {
|
|
4244
4859
|
const sections = presentGroups(analysis).map((group) => {
|
|
4245
4860
|
const metrics = analysis.metrics.filter((metric) => metric.group === group.id);
|
|
4246
|
-
const cards = metrics.map((metric) =>
|
|
4861
|
+
const cards = metrics.map((metric) => metricCard2(metric, explanations)).join("\n");
|
|
4247
4862
|
return `<section id="group-${group.id.toLowerCase()}" class="metric-group" aria-labelledby="group-${group.id.toLowerCase()}-h">
|
|
4248
|
-
<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>
|
|
4249
4864
|
${groupOverviewPanel(group.id, metrics)}
|
|
4865
|
+
<div class="cards">
|
|
4250
4866
|
${cards}
|
|
4867
|
+
</div>
|
|
4251
4868
|
</section>`;
|
|
4252
4869
|
});
|
|
4253
4870
|
return `<main id="main" class="metric-groups">
|
|
4254
4871
|
${sections.join("\n")}
|
|
4255
4872
|
</main>`;
|
|
4256
4873
|
}
|
|
4257
|
-
function
|
|
4874
|
+
function metricCard2(metric, explanations) {
|
|
4258
4875
|
const band = classifyHealth(metric);
|
|
4259
4876
|
const bandHtml = `<span class="health health-${band}"><span class="health-glyph" aria-hidden="true">${HEALTH_GLYPH[band]}</span> ${escapeHtml(HEALTH_LABEL[band])}</span>`;
|
|
4260
|
-
const
|
|
4877
|
+
const stat = metricStat(metric);
|
|
4878
|
+
const statHtml = stat === "" ? "" : `<span class="metric-stat">${escapeHtml(stat)}</span>`;
|
|
4261
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>`;
|
|
4262
4882
|
return `<details class="metric-card" data-status="${escapeHtml(metric.status)}" data-health="${band}" open>
|
|
4263
|
-
<summary><h3 class="metric-title">${escapeHtml(metric.title)}</h3> ${bandHtml}</summary>
|
|
4883
|
+
<summary><h3 class="metric-title">${escapeHtml(metric.title)}</h3> ${bandHtml}${statHtml}</summary>
|
|
4264
4884
|
<div class="metric-body">
|
|
4265
|
-
${
|
|
4266
|
-
${
|
|
4267
|
-
${explanation === void 0 ? "" : fourFacets(explanation)}
|
|
4885
|
+
${reason}
|
|
4886
|
+
${facets}
|
|
4268
4887
|
</div>
|
|
4269
4888
|
</details>`;
|
|
4270
4889
|
}
|
|
@@ -4288,94 +4907,247 @@ ${list(explanation.needsImprovement)}
|
|
|
4288
4907
|
${list(explanation.suggestions)}
|
|
4289
4908
|
</div>`;
|
|
4290
4909
|
}
|
|
4291
|
-
function
|
|
4292
|
-
if (
|
|
4910
|
+
function metricStat(metric) {
|
|
4911
|
+
if (metric.status !== "computed") {
|
|
4293
4912
|
return "";
|
|
4294
4913
|
}
|
|
4914
|
+
const value = metric.value;
|
|
4915
|
+
if (typeof value === "number") {
|
|
4916
|
+
return Number.isFinite(value) ? fmtStat(value) : "";
|
|
4917
|
+
}
|
|
4295
4918
|
if (typeof value === "string") {
|
|
4296
4919
|
return value;
|
|
4297
4920
|
}
|
|
4298
|
-
const
|
|
4299
|
-
|
|
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 "";
|
|
4300
4938
|
}
|
|
4301
|
-
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
|
+
}
|
|
4302
4953
|
return `<footer class="footer">
|
|
4303
|
-
<p
|
|
4954
|
+
<p>${parts.join(" \xB7 ")}</p>
|
|
4304
4955
|
</footer>`;
|
|
4305
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
|
+
}
|
|
4306
4975
|
var STYLE = `
|
|
4307
4976
|
:root {
|
|
4308
4977
|
color-scheme: dark light;
|
|
4309
|
-
--bg: #
|
|
4310
|
-
--
|
|
4311
|
-
--
|
|
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);
|
|
4312
4984
|
}
|
|
4313
4985
|
@media (prefers-color-scheme: light) {
|
|
4314
4986
|
:root {
|
|
4315
|
-
--bg: #ffffff; --surface: #f6f8fa; --
|
|
4316
|
-
--
|
|
4317
|
-
--
|
|
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);
|
|
4318
4993
|
}
|
|
4319
4994
|
}
|
|
4320
4995
|
* { box-sizing: border-box; }
|
|
4321
4996
|
body {
|
|
4322
|
-
margin: 0; padding: 0
|
|
4323
|
-
background:
|
|
4324
|
-
|
|
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;
|
|
4325
5004
|
line-height: 1.6;
|
|
5005
|
+
-webkit-font-smoothing: antialiased;
|
|
4326
5006
|
}
|
|
4327
|
-
main, header, nav, section, footer { max-width:
|
|
4328
|
-
h1 { font-size: 2rem; margin: 1.5rem 0 0.25rem; }
|
|
4329
|
-
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; }
|
|
4330
5010
|
h3 { font-size: 1.1rem; margin: 1.25rem 0 0.5rem; }
|
|
4331
|
-
h4 { font-size: 0.
|
|
4332
|
-
a { color: var(--accent); }
|
|
4333
|
-
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; }
|
|
4334
5015
|
.skip-link {
|
|
4335
5016
|
position: absolute; left: -9999px; top: 0;
|
|
4336
|
-
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;
|
|
4337
5018
|
}
|
|
4338
5019
|
.skip-link:focus { left: 0; }
|
|
4339
|
-
.
|
|
4340
|
-
.
|
|
4341
|
-
.
|
|
4342
|
-
|
|
4343
|
-
|
|
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); }
|
|
4344
5057
|
.confidence-escalation { color: var(--risk); font-weight: 600; }
|
|
4345
|
-
.banner { border-radius:
|
|
4346
|
-
.banner-degraded { border: 1px solid
|
|
4347
|
-
.banner-metrics-only { border: 1px solid var(--border); color: var(--muted); }
|
|
4348
|
-
.toc {
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
:
|
|
4352
|
-
|
|
4353
|
-
.
|
|
4354
|
-
.
|
|
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; }
|
|
4355
5089
|
.metric-card[data-health="risk"] { border-left: 4px solid var(--risk); }
|
|
4356
5090
|
.metric-card[data-health="watch"] { border-left: 4px solid var(--watch); }
|
|
4357
|
-
.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); }
|
|
4358
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; }
|
|
4359
5096
|
.metric-body { margin-top: 0.5rem; }
|
|
4360
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; }
|
|
4361
5099
|
.metric-card code { word-break: break-word; }
|
|
5100
|
+
.facets { margin-top: 0.6rem; }
|
|
5101
|
+
.facet-meaning { color: var(--fg-soft); }
|
|
4362
5102
|
.facets ul { margin: 0.25rem 0 0.5rem; }
|
|
4363
|
-
.health { font-size: 0.
|
|
4364
|
-
.health-glyph { font-size:
|
|
4365
|
-
.health-ok { color: var(--ok); }
|
|
4366
|
-
.health-watch { color: var(--watch); }
|
|
4367
|
-
.health-risk { color: var(--risk); }
|
|
4368
|
-
.health-na { color: var(--
|
|
4369
|
-
.chart-panel { margin: 1rem 0; background: var(--surface); border: 1px solid var(--border); border-radius:
|
|
4370
|
-
.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; }
|
|
4371
5111
|
.chart-source { font-style: italic; }
|
|
4372
5112
|
.chart-empty { color: var(--muted); }
|
|
4373
|
-
.chart-svg { width: 100%; height:
|
|
4374
|
-
.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); }
|
|
4375
5128
|
.chart-svg .bar { fill: var(--accent); }
|
|
4376
5129
|
.chart-svg .gauge-track { fill: var(--border); }
|
|
4377
5130
|
.chart-svg .gauge-fill { fill: var(--accent); }
|
|
4378
|
-
.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; } }
|
|
4379
5151
|
.metric-visual { margin: 0.5rem 0; }
|
|
4380
5152
|
.metric-visual-range { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
|
|
4381
5153
|
.metric-number { font-size: 1.4rem; font-weight: 700; }
|
|
@@ -4384,13 +5156,12 @@ a:focus-visible, :focus-visible { outline: 2px solid var(--accent); outline-offs
|
|
|
4384
5156
|
.data-table table { border-collapse: collapse; width: 100%; font-size: 0.85rem; margin-top: 0.5rem; }
|
|
4385
5157
|
.data-table th, .data-table td { border: 1px solid var(--border); padding: 0.25rem 0.5rem; text-align: left; }
|
|
4386
5158
|
.data-table caption { text-align: left; color: var(--muted); padding-bottom: 0.25rem; }
|
|
4387
|
-
.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; }
|
|
4388
5160
|
@media (prefers-reduced-motion: reduce) {
|
|
4389
5161
|
* { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; }
|
|
4390
5162
|
}
|
|
4391
5163
|
`;
|
|
4392
5164
|
var DISCLOSURE_SCRIPT = `
|
|
4393
|
-
document.querySelectorAll('details.metric-card[data-health="ok"]').forEach(function(d){d.open=false;});
|
|
4394
5165
|
document.querySelectorAll('details.data-table').forEach(function(d){d.open=false;});
|
|
4395
5166
|
`;
|
|
4396
5167
|
|
|
@@ -4429,7 +5200,7 @@ function safe2(n) {
|
|
|
4429
5200
|
function round2(n) {
|
|
4430
5201
|
return Math.round(safe2(n) * 100) / 100;
|
|
4431
5202
|
}
|
|
4432
|
-
function
|
|
5203
|
+
function extent(values) {
|
|
4433
5204
|
let min = Number.POSITIVE_INFINITY;
|
|
4434
5205
|
let max = Number.NEGATIVE_INFINITY;
|
|
4435
5206
|
for (const raw of values) {
|
|
@@ -4445,7 +5216,7 @@ function sparkline(series) {
|
|
|
4445
5216
|
return "";
|
|
4446
5217
|
}
|
|
4447
5218
|
const values = series.map((p) => safe2(p.value));
|
|
4448
|
-
const [min, max] =
|
|
5219
|
+
const [min, max] = extent(values);
|
|
4449
5220
|
const span = max - min;
|
|
4450
5221
|
const midGlyph = SPARK_GLYPHS[Math.floor(SPARK_GLYPHS.length / 2)];
|
|
4451
5222
|
if (span === 0) {
|
|
@@ -4462,7 +5233,7 @@ function textBars(series) {
|
|
|
4462
5233
|
if (series.length === 0) {
|
|
4463
5234
|
return "";
|
|
4464
5235
|
}
|
|
4465
|
-
const [, max] =
|
|
5236
|
+
const [, max] = extent(series.map((p) => p.value));
|
|
4466
5237
|
const top = max <= 0 ? 1 : max;
|
|
4467
5238
|
const labels = series.map((p) => escapeCell(p.label));
|
|
4468
5239
|
const labelWidth = labels.reduce((w, label) => Math.max(w, label.length), 0);
|
|
@@ -4494,7 +5265,7 @@ function mermaidXychart(series, title2) {
|
|
|
4494
5265
|
"```"
|
|
4495
5266
|
].join("\n");
|
|
4496
5267
|
}
|
|
4497
|
-
function
|
|
5268
|
+
function representativeSeries(metrics) {
|
|
4498
5269
|
for (const metric of metrics) {
|
|
4499
5270
|
if (metric.status !== "computed") {
|
|
4500
5271
|
continue;
|
|
@@ -4511,7 +5282,7 @@ function representativeSeries2(metrics) {
|
|
|
4511
5282
|
return void 0;
|
|
4512
5283
|
}
|
|
4513
5284
|
function groupOverview(group, metrics) {
|
|
4514
|
-
const rep =
|
|
5285
|
+
const rep = representativeSeries(metrics);
|
|
4515
5286
|
if (rep === void 0) {
|
|
4516
5287
|
return GROUP_OVERVIEW_NONE;
|
|
4517
5288
|
}
|
|
@@ -4555,7 +5326,7 @@ function metricVisualMarkdown(metric) {
|
|
|
4555
5326
|
}
|
|
4556
5327
|
|
|
4557
5328
|
// src/render/markdown/markdown-renderer.ts
|
|
4558
|
-
var
|
|
5329
|
+
var GROUPS3 = [
|
|
4559
5330
|
{ id: "A", title: "Activity & Cadence", description: "How the project moves over time." },
|
|
4560
5331
|
{ id: "B", title: "Contribution & Ownership", description: "How the work is distributed across the team." },
|
|
4561
5332
|
{ id: "C", title: "Commit Message Quality", description: "How clearly the history communicates intent." },
|
|
@@ -4567,42 +5338,100 @@ var MD_DEGRADED_BANNER = "> \u26A0 **Narrative unavailable \u2014 showing raw an
|
|
|
4567
5338
|
var MD_METRICS_ONLY_NOTE = "_Narrative skipped (--no-ai) \u2014 run interactively or add a key for the full report._";
|
|
4568
5339
|
function renderMarkdown(report) {
|
|
4569
5340
|
const route = classifyReport(report);
|
|
4570
|
-
const
|
|
5341
|
+
const provenance = report.provenance;
|
|
5342
|
+
const body = route.kind === "showpiece" ? renderShowpiece3(route.report, provenance) : renderSubstrate3(route.analysis, route.framing, provenance);
|
|
4571
5343
|
return `${body}
|
|
4572
5344
|
`;
|
|
4573
5345
|
}
|
|
4574
5346
|
function blocks(...parts) {
|
|
4575
5347
|
return parts.filter((part) => part !== "").join("\n\n");
|
|
4576
5348
|
}
|
|
4577
|
-
function renderShowpiece3(report) {
|
|
5349
|
+
function renderShowpiece3(report, provenance) {
|
|
4578
5350
|
const { summary, explanation, coaching, explanations, confidence } = report.narrative;
|
|
4579
5351
|
return blocks(
|
|
4580
|
-
|
|
5352
|
+
masthead3(provenance),
|
|
4581
5353
|
confidence === void 0 ? "" : confidenceBlock(confidence),
|
|
4582
5354
|
summaryBand2(summary),
|
|
4583
5355
|
explanationBand2(explanation),
|
|
4584
5356
|
coachingBand2(coaching),
|
|
4585
|
-
|
|
4586
|
-
footer2("showpiece")
|
|
5357
|
+
metricsSection2(report.analysis, explanations),
|
|
5358
|
+
footer2("showpiece", provenance)
|
|
4587
5359
|
);
|
|
4588
5360
|
}
|
|
4589
|
-
function renderSubstrate3(analysis, framing) {
|
|
5361
|
+
function renderSubstrate3(analysis, framing, provenance) {
|
|
4590
5362
|
if (framing === "degraded") {
|
|
4591
5363
|
return blocks(
|
|
4592
5364
|
MD_DEGRADED_BANNER,
|
|
4593
|
-
|
|
5365
|
+
masthead3(provenance),
|
|
4594
5366
|
"**Confidence:** \u2014 _(no narrative to assess)_",
|
|
4595
5367
|
stubBand("Summary", "Narrative unavailable \u2014 showing raw analysis."),
|
|
4596
5368
|
stubBand("Explanation", "Narrative unavailable."),
|
|
4597
5369
|
stubBand("Coaching", "Narrative unavailable."),
|
|
4598
|
-
|
|
4599
|
-
footer2("degraded")
|
|
5370
|
+
metricsSection2(analysis, void 0),
|
|
5371
|
+
footer2("degraded", provenance)
|
|
4600
5372
|
);
|
|
4601
5373
|
}
|
|
4602
|
-
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;
|
|
4603
5432
|
}
|
|
4604
|
-
function
|
|
4605
|
-
return
|
|
5433
|
+
function isoDate3(iso) {
|
|
5434
|
+
return iso.slice(0, 10);
|
|
4606
5435
|
}
|
|
4607
5436
|
function confidenceBlock(confidence) {
|
|
4608
5437
|
const head = `**Confidence:** ${confidence.level} \u2014 ${inlineProse(confidence.rationale)}`;
|
|
@@ -4649,14 +5478,14 @@ function stubBand(name, note) {
|
|
|
4649
5478
|
|
|
4650
5479
|
_${note}_`;
|
|
4651
5480
|
}
|
|
4652
|
-
function
|
|
4653
|
-
const present =
|
|
5481
|
+
function metricsSection2(analysis, explanations) {
|
|
5482
|
+
const present = GROUPS3.filter((group) => analysis.metrics.some((metric) => metric.group === group.id));
|
|
4654
5483
|
if (present.length === 0) {
|
|
4655
5484
|
return "## Metrics\n\n_No metrics computed._";
|
|
4656
5485
|
}
|
|
4657
5486
|
const sections = present.map((group) => {
|
|
4658
5487
|
const metrics = analysis.metrics.filter((metric) => metric.group === group.id);
|
|
4659
|
-
const cards = metrics.map((metric) =>
|
|
5488
|
+
const cards = metrics.map((metric) => metricCard3(metric, explanations)).join("\n\n");
|
|
4660
5489
|
const overview = groupOverview(group.id, metrics);
|
|
4661
5490
|
return `### ${group.id} \xB7 ${escapeCell(group.title)}
|
|
4662
5491
|
|
|
@@ -4670,42 +5499,42 @@ ${cards}`;
|
|
|
4670
5499
|
|
|
4671
5500
|
${sections.join("\n\n")}`;
|
|
4672
5501
|
}
|
|
4673
|
-
function
|
|
5502
|
+
function metricCard3(metric, explanations) {
|
|
4674
5503
|
const band = classifyHealth(metric);
|
|
4675
5504
|
const visual = metricVisualMarkdown(metric);
|
|
4676
5505
|
const suffix = visual.headingSuffix === "" ? "" : ` ${visual.headingSuffix}`;
|
|
4677
|
-
const
|
|
5506
|
+
const heading = `#### ${escapeCell(metric.title)} ${HEALTH_GLYPH[band]} ${HEALTH_LABEL[band]}${suffix}`;
|
|
4678
5507
|
const body = visual.body === "" ? "" : `
|
|
4679
5508
|
|
|
4680
5509
|
${visual.body}`;
|
|
4681
|
-
return `${
|
|
5510
|
+
return `${heading}${body}
|
|
4682
5511
|
|
|
4683
5512
|
${metricBullets(metric, explanations)}`;
|
|
4684
5513
|
}
|
|
4685
5514
|
function metricBullets(metric, explanations) {
|
|
4686
|
-
const value =
|
|
5515
|
+
const value = valueBullet2(metric);
|
|
4687
5516
|
const explanation = explanations?.[metric.id];
|
|
4688
5517
|
if (explanation === void 0) {
|
|
4689
5518
|
return value;
|
|
4690
5519
|
}
|
|
4691
|
-
return [value, ...
|
|
5520
|
+
return [value, ...facetBullets2(explanation)].join("\n");
|
|
4692
5521
|
}
|
|
4693
|
-
function
|
|
5522
|
+
function valueBullet2(metric) {
|
|
4694
5523
|
if (metric.status !== "computed") {
|
|
4695
5524
|
const reason = metric.reason === void 0 ? "" : ` \u2014 ${escapeCell(metric.reason)}`;
|
|
4696
5525
|
return `- **Value** \u2014 _not available${reason}_`;
|
|
4697
5526
|
}
|
|
4698
5527
|
return `- **Value** \u2014 ${escapeCell(formatValue3(metric.value))}`;
|
|
4699
5528
|
}
|
|
4700
|
-
function
|
|
5529
|
+
function facetBullets2(explanation) {
|
|
4701
5530
|
return [
|
|
4702
5531
|
`- **What it means** \u2014 ${inlineProse(explanation.explanation)}`,
|
|
4703
|
-
...
|
|
4704
|
-
...
|
|
4705
|
-
...
|
|
5532
|
+
...arrayFacet2("Strengths", explanation.goodBehaviours),
|
|
5533
|
+
...arrayFacet2("Needs improvement", explanation.needsImprovement),
|
|
5534
|
+
...arrayFacet2("Suggestions", explanation.suggestions)
|
|
4706
5535
|
];
|
|
4707
5536
|
}
|
|
4708
|
-
function
|
|
5537
|
+
function arrayFacet2(label, items) {
|
|
4709
5538
|
if (items.length === 0) {
|
|
4710
5539
|
return [`- **${label}** \u2014 \u2014`];
|
|
4711
5540
|
}
|
|
@@ -4723,8 +5552,22 @@ function formatValue3(value) {
|
|
|
4723
5552
|
}
|
|
4724
5553
|
return JSON.stringify(value) ?? "";
|
|
4725
5554
|
}
|
|
4726
|
-
function footer2(kind) {
|
|
4727
|
-
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 ")}`;
|
|
4728
5571
|
return kind === "metrics-only" ? `${base}
|
|
4729
5572
|
|
|
4730
5573
|
${MD_METRICS_ONLY_NOTE}` : base;
|
|
@@ -5087,6 +5930,88 @@ function createRetrieve(deps = {}) {
|
|
|
5087
5930
|
return async (config) => (isRemoteTarget(config.repoTarget) ? remote : local)(config);
|
|
5088
5931
|
}
|
|
5089
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
|
+
|
|
5090
6015
|
// src/cli/write-file.ts
|
|
5091
6016
|
import { writeFile as fsWriteFile } from "fs/promises";
|
|
5092
6017
|
var defaultWriteFile = async (path, content) => {
|
|
@@ -5099,6 +6024,7 @@ async function runPipeline(config, deps = {}) {
|
|
|
5099
6024
|
const narrate = deps.narrate ?? createNarrate();
|
|
5100
6025
|
const preflight = deps.preflight ?? preflightProvider;
|
|
5101
6026
|
const ui2 = deps.ui ?? ui;
|
|
6027
|
+
const progress = deps.progress ?? noopProgress;
|
|
5102
6028
|
const writeStdout2 = deps.writeStdout ?? ((text) => {
|
|
5103
6029
|
process.stdout.write(text);
|
|
5104
6030
|
});
|
|
@@ -5116,7 +6042,8 @@ async function runPipeline(config, deps = {}) {
|
|
|
5116
6042
|
if (config.aiMode === "off" && config.provenance.aiMode === "default") {
|
|
5117
6043
|
ui2.info("Running metrics-only \u2014 for the AI narrative, run interactively or set a provider key.");
|
|
5118
6044
|
}
|
|
5119
|
-
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}`);
|
|
5120
6047
|
ui2.debug?.(`Retrieved ${history.commits.length} commit(s) from ${history.repoTarget}.`);
|
|
5121
6048
|
const selection = selectCommitsWithNotice(history, projectSelection(config));
|
|
5122
6049
|
if (selection.truncation !== void 0) {
|
|
@@ -5129,17 +6056,60 @@ async function runPipeline(config, deps = {}) {
|
|
|
5129
6056
|
mailmap: emptyMailmap()
|
|
5130
6057
|
// real .mailmap ingestion is deferred
|
|
5131
6058
|
};
|
|
5132
|
-
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)`);
|
|
5133
6061
|
ui2.debug?.(`Analyzed ${selection.history.commits.length} commit(s); aiMode=${config.aiMode}.`);
|
|
5134
|
-
const outcome = await
|
|
5135
|
-
|
|
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);
|
|
5136
6081
|
const targets = planOutputs(config.outputFormats, config.outputPath);
|
|
6082
|
+
progress.start("Rendering report\u2026");
|
|
6083
|
+
progress.done("Report ready");
|
|
5137
6084
|
const htmlFilePath = await emitOutputs(report, targets, { writeStdout: writeStdout2, writeFile: writeFile3, ui: ui2 });
|
|
5138
6085
|
if (autoOpen && htmlFilePath !== void 0) {
|
|
5139
6086
|
await tryOpen(openBrowser, htmlFilePath, ui2);
|
|
5140
6087
|
}
|
|
5141
6088
|
return report.degraded ? ExitCode.Degraded : ExitCode.Success;
|
|
5142
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
|
+
}
|
|
5143
6113
|
async function emitOutputs(report, targets, io) {
|
|
5144
6114
|
let htmlFilePath;
|
|
5145
6115
|
for (const target of targets) {
|
|
@@ -5208,6 +6178,14 @@ async function narrateOutcome(config, narrateConfig, analysis, narrate, prefligh
|
|
|
5208
6178
|
}
|
|
5209
6179
|
return narrate(analysis, narrateConfig);
|
|
5210
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
|
+
}
|
|
5211
6189
|
|
|
5212
6190
|
// src/cli/show-config.ts
|
|
5213
6191
|
var UNSET = "(unset)";
|
|
@@ -5263,9 +6241,6 @@ function formatShowConfig(config, secrets) {
|
|
|
5263
6241
|
return lines.join("\n");
|
|
5264
6242
|
}
|
|
5265
6243
|
|
|
5266
|
-
// src/cli/version.ts
|
|
5267
|
-
var VERSION = "1.0.8";
|
|
5268
|
-
|
|
5269
6244
|
// src/cli/cli.ts
|
|
5270
6245
|
var PROVIDERS3 = ["ollama", "openai", "gemini", "anthropic", "openai-compatible"];
|
|
5271
6246
|
var OUTPUT_FORMATS3 = ["terminal", "html", "markdown", "json"];
|
|
@@ -5314,7 +6289,7 @@ async function main(argv, deps = {}) {
|
|
|
5314
6289
|
});
|
|
5315
6290
|
try {
|
|
5316
6291
|
if (argv.length === 0) {
|
|
5317
|
-
return await runZeroArg({ deps, ui: ui2, env, cwd, stdinIsTTY, stdoutIsTTY });
|
|
6292
|
+
return await runZeroArg({ deps, ui: ui2, env, cwd, stdinIsTTY, stdoutIsTTY, stderrIsTTY });
|
|
5318
6293
|
}
|
|
5319
6294
|
const program = buildProgram();
|
|
5320
6295
|
try {
|
|
@@ -5350,10 +6325,10 @@ async function main(argv, deps = {}) {
|
|
|
5350
6325
|
return ExitCode.Success;
|
|
5351
6326
|
}
|
|
5352
6327
|
const entitlement = entitlementForHeadlessRun(resolution);
|
|
5353
|
-
const
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
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);
|
|
5357
6332
|
const config = resolveRunConfig({
|
|
5358
6333
|
cwd,
|
|
5359
6334
|
env,
|
|
@@ -5376,7 +6351,8 @@ async function main(argv, deps = {}) {
|
|
|
5376
6351
|
openAllowed: opts.open !== false,
|
|
5377
6352
|
// honoured only when interactive (false here)
|
|
5378
6353
|
deps,
|
|
5379
|
-
ui: runUi
|
|
6354
|
+
ui: runUi,
|
|
6355
|
+
progress
|
|
5380
6356
|
});
|
|
5381
6357
|
} catch (err) {
|
|
5382
6358
|
ui2.error(messageForError(err));
|
|
@@ -5413,7 +6389,8 @@ async function resolveAndRun(input) {
|
|
|
5413
6389
|
nonInteractive: input.nonInteractive,
|
|
5414
6390
|
openAllowed: input.openAllowed,
|
|
5415
6391
|
deps: input.deps,
|
|
5416
|
-
ui: input.ui
|
|
6392
|
+
ui: input.ui,
|
|
6393
|
+
progress: input.progress
|
|
5417
6394
|
});
|
|
5418
6395
|
}
|
|
5419
6396
|
async function runResolved(input) {
|
|
@@ -5431,11 +6408,21 @@ async function runResolved(input) {
|
|
|
5431
6408
|
aiKey,
|
|
5432
6409
|
gitToken,
|
|
5433
6410
|
ui: input.ui,
|
|
6411
|
+
progress: input.progress,
|
|
5434
6412
|
writeStdout: input.deps.writeStdout,
|
|
5435
6413
|
autoOpen,
|
|
5436
6414
|
...input.deps.runDeps
|
|
5437
6415
|
});
|
|
5438
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
|
+
}
|
|
5439
6426
|
async function runZeroArg(ctx) {
|
|
5440
6427
|
const { interactive } = detectCapability({
|
|
5441
6428
|
nonInteractive: false,
|
|
@@ -5473,6 +6460,7 @@ async function runZeroArg(ctx) {
|
|
|
5473
6460
|
};
|
|
5474
6461
|
const runAnalysis = async (flags) => {
|
|
5475
6462
|
try {
|
|
6463
|
+
const liveConfigFile = ctx.deps.configFile ?? await readSettings(ctx.env);
|
|
5476
6464
|
return await resolveAndRun({
|
|
5477
6465
|
flags,
|
|
5478
6466
|
env: ctx.env,
|
|
@@ -5482,24 +6470,67 @@ async function runZeroArg(ctx) {
|
|
|
5482
6470
|
analysisTimestamp: ctx.deps.analysisTimestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
5483
6471
|
nonInteractive: false,
|
|
5484
6472
|
openAllowed: true,
|
|
5485
|
-
configFile,
|
|
6473
|
+
configFile: liveConfigFile,
|
|
5486
6474
|
entitlement,
|
|
5487
6475
|
deps: ctx.deps,
|
|
5488
|
-
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
|
+
)
|
|
5489
6483
|
});
|
|
5490
6484
|
} catch (err) {
|
|
5491
6485
|
ctx.ui.error(messageForError(err));
|
|
5492
6486
|
return exitCodeForError(err);
|
|
5493
6487
|
}
|
|
5494
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
|
+
});
|
|
5495
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
|
+
};
|
|
5496
6526
|
const probeReachability = async () => {
|
|
6527
|
+
const live = await resolveLiveAi();
|
|
5497
6528
|
const narrateConfig = {
|
|
5498
6529
|
aiMode: "auto",
|
|
5499
|
-
provider:
|
|
5500
|
-
llmModel:
|
|
5501
|
-
llmBaseUrl:
|
|
5502
|
-
aiKey: readAiKey(ctx.env,
|
|
6530
|
+
provider: live.provider,
|
|
6531
|
+
llmModel: live.llmModel,
|
|
6532
|
+
llmBaseUrl: live.llmBaseUrl,
|
|
6533
|
+
aiKey: readAiKey(ctx.env, live.provider)
|
|
5503
6534
|
};
|
|
5504
6535
|
const result = await (ctx.deps.preflight ?? preflightProvider)(narrateConfig, {});
|
|
5505
6536
|
return result.reachable ? { kind: "reachable" } : { kind: "unreachable", reason: result.reason };
|
|
@@ -5512,8 +6543,21 @@ async function runZeroArg(ctx) {
|
|
|
5512
6543
|
gitTokenConfigured: readGitToken(ctx.env) !== void 0,
|
|
5513
6544
|
envDiagnostics,
|
|
5514
6545
|
probeReachability,
|
|
6546
|
+
doctorConfig,
|
|
6547
|
+
refreshDoctor,
|
|
5515
6548
|
loadSettings: () => readSettings(ctx.env),
|
|
5516
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
|
+
},
|
|
5517
6561
|
// License actions (Story 7.2): the only in-app key entry + the browser hand-offs.
|
|
5518
6562
|
activateLicense: (key) => (ctx.deps.activateLicense ?? defaultActivateLicense)(ctx.env, key),
|
|
5519
6563
|
deactivateLicense: () => (ctx.deps.deactivateLicense ?? defaultDeactivateLicense)(ctx.env),
|