vibe-splain 3.3.1 → 3.4.1
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 +85 -35
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -321,8 +321,10 @@ function inferProductDomain(relPath, importSpecs) {
|
|
|
321
321
|
}
|
|
322
322
|
if (p.includes("booking-audit") || p.includes("bookingaudit"))
|
|
323
323
|
return "booking_audit";
|
|
324
|
-
if (p.includes("
|
|
324
|
+
if (p.includes("/pages/api/book/") || p.includes("/api/book/") || p.includes("/booking-successful/") || p.includes("/reschedule/") || p.includes("booking-page-wrapper"))
|
|
325
325
|
return "booking_creation";
|
|
326
|
+
if (p.includes("bookeventform") || p.includes("availabletimes") || p.includes("availabletimeslots") || p.includes("usebookings") || p.includes("/book/") && !p.includes("booking-audit"))
|
|
327
|
+
return "booking_ui_delegate";
|
|
326
328
|
if (p.includes("modules/bookings") || p.includes("components/booking/actions") || p.includes("/bookings/[status]") || p.includes("/booking/[uid]") || p.includes("/bookings/"))
|
|
327
329
|
return "booking_management";
|
|
328
330
|
if (p.includes("event-types") || p.includes("eventtypes") || p.includes("eventavailabilitytab") || p.includes("eventadvancedtab") || p.includes("eventlimits") || p.includes("eventrecurring"))
|
|
@@ -1043,7 +1045,17 @@ function analyzeAst(source, lang, tree) {
|
|
|
1043
1045
|
for (const fn of fnNodes) {
|
|
1044
1046
|
const bodyLOC = nodeLOC(fn);
|
|
1045
1047
|
const decisions = countDecisions(fn);
|
|
1046
|
-
|
|
1048
|
+
let score = decisions + bodyLOC;
|
|
1049
|
+
const text = fn.text;
|
|
1050
|
+
if (lang === "typescript" || lang === "tsx" || lang === "javascript") {
|
|
1051
|
+
if (/stripe|webhook|payload|signature|event/i.test(text) && /switch|case|if/i.test(text)) {
|
|
1052
|
+
score += 25;
|
|
1053
|
+
}
|
|
1054
|
+
if (text.includes("prisma") && (text.includes("create") || text.includes("update"))) {
|
|
1055
|
+
score += 10;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
scored.push({ node: fn, decisions, bodyLOC, score });
|
|
1047
1059
|
if (bodyLOC > LONG_FN_LOC) {
|
|
1048
1060
|
longFunctions++;
|
|
1049
1061
|
smells.push({
|
|
@@ -1073,7 +1085,7 @@ function analyzeAst(source, lang, tree) {
|
|
|
1073
1085
|
});
|
|
1074
1086
|
}
|
|
1075
1087
|
scored.sort((a, b) => b.score - a.score);
|
|
1076
|
-
const hotSpans = scored.slice(0, 3).filter((s) => s.bodyLOC >=
|
|
1088
|
+
const hotSpans = scored.slice(0, 3).filter((s) => s.bodyLOC >= 2).map((s) => {
|
|
1077
1089
|
const rawExcerpt = source.split("\n").slice(s.node.startPosition.row, s.node.endPosition.row + 1).join("\n");
|
|
1078
1090
|
const snippet = stripLeadingComments(rawExcerpt).slice(0, 2e3);
|
|
1079
1091
|
return {
|
|
@@ -1240,9 +1252,25 @@ async function extractTsConfigPaths(tsconfigPath, projectRoot, depth = 0) {
|
|
|
1240
1252
|
if (baseFile.startsWith(".")) {
|
|
1241
1253
|
baseFile = join3(dirname2(tsconfigPath), baseFile);
|
|
1242
1254
|
} else {
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1255
|
+
let currentDir = dirname2(tsconfigPath);
|
|
1256
|
+
let found = false;
|
|
1257
|
+
while (currentDir.length >= projectRoot.length || currentDir === projectRoot) {
|
|
1258
|
+
const candidate = join3(currentDir, "node_modules", baseFile + (baseFile.endsWith(".json") ? "" : ".json"));
|
|
1259
|
+
if (existsSync3(candidate)) {
|
|
1260
|
+
baseFile = candidate;
|
|
1261
|
+
found = true;
|
|
1262
|
+
break;
|
|
1263
|
+
}
|
|
1264
|
+
const parent = dirname2(currentDir);
|
|
1265
|
+
if (parent === currentDir)
|
|
1266
|
+
break;
|
|
1267
|
+
currentDir = parent;
|
|
1268
|
+
}
|
|
1269
|
+
if (!found) {
|
|
1270
|
+
baseFile = join3(projectRoot, "node_modules", baseFile);
|
|
1271
|
+
if (!baseFile.endsWith(".json"))
|
|
1272
|
+
baseFile += ".json";
|
|
1273
|
+
}
|
|
1246
1274
|
}
|
|
1247
1275
|
const base = await extractTsConfigPaths(baseFile, projectRoot, depth + 1);
|
|
1248
1276
|
Object.assign(result, base);
|
|
@@ -1309,17 +1337,20 @@ async function discoverWorkspacePackages(projectRoot) {
|
|
|
1309
1337
|
return packages;
|
|
1310
1338
|
}
|
|
1311
1339
|
var CONVENTIONAL_ALIASES = [
|
|
1340
|
+
{ prefix: "~/", replacement: "modules/" },
|
|
1312
1341
|
{ prefix: "~/", replacement: "" },
|
|
1342
|
+
{ prefix: "@calcom/web/", replacement: "" },
|
|
1343
|
+
{ prefix: "@calcom/web/", replacement: "modules/" },
|
|
1313
1344
|
{ prefix: "@components/", replacement: "components/" },
|
|
1314
1345
|
{ prefix: "@lib/", replacement: "lib/" },
|
|
1315
1346
|
{ prefix: "@server/", replacement: "server/" },
|
|
1316
|
-
{ prefix: "@calcom/
|
|
1347
|
+
{ prefix: "@calcom/features/", replacement: "../../packages/features/src/" },
|
|
1317
1348
|
{ prefix: "@calcom/features/", replacement: "../packages/features/" },
|
|
1318
|
-
{ prefix: "@calcom/lib/", replacement: "
|
|
1319
|
-
{ prefix: "@calcom/prisma/", replacement: "
|
|
1320
|
-
{ prefix: "@calcom/trpc/", replacement: "
|
|
1321
|
-
{ prefix: "@calcom/ui/", replacement: "
|
|
1322
|
-
{ prefix: "@calcom/emails/", replacement: "
|
|
1349
|
+
{ prefix: "@calcom/lib/", replacement: "../../packages/lib/" },
|
|
1350
|
+
{ prefix: "@calcom/prisma/", replacement: "../../packages/prisma/" },
|
|
1351
|
+
{ prefix: "@calcom/trpc/", replacement: "../../packages/trpc/" },
|
|
1352
|
+
{ prefix: "@calcom/ui/", replacement: "../../packages/ui/" },
|
|
1353
|
+
{ prefix: "@calcom/emails/", replacement: "../../packages/emails/" }
|
|
1323
1354
|
];
|
|
1324
1355
|
async function buildAliasMap(projectRoot) {
|
|
1325
1356
|
const allPaths = await discoverAllTsConfigs(projectRoot, projectRoot);
|
|
@@ -1416,8 +1447,10 @@ function resolveImportWithAliasMap(spec, fromAbs, lang, projectRoot, fileSet, ba
|
|
|
1416
1447
|
return { resolved, isAlias: true };
|
|
1417
1448
|
}
|
|
1418
1449
|
}
|
|
1450
|
+
let matchedPrefix = false;
|
|
1419
1451
|
for (const { prefix, replacement } of CONVENTIONAL_ALIASES) {
|
|
1420
1452
|
if (spec.startsWith(prefix)) {
|
|
1453
|
+
matchedPrefix = true;
|
|
1421
1454
|
const rest = replacement + spec.slice(prefix.length);
|
|
1422
1455
|
const base = join3(projectRoot, rest);
|
|
1423
1456
|
const resolved = tryJsCandidates(base, projectRoot, fileSet);
|
|
@@ -1425,6 +1458,8 @@ function resolveImportWithAliasMap(spec, fromAbs, lang, projectRoot, fileSet, ba
|
|
|
1425
1458
|
return { resolved, isAlias: true };
|
|
1426
1459
|
}
|
|
1427
1460
|
}
|
|
1461
|
+
if (matchedPrefix)
|
|
1462
|
+
return { resolved: null, isAlias: true };
|
|
1428
1463
|
return { resolved: null, isAlias: false };
|
|
1429
1464
|
}
|
|
1430
1465
|
return { resolved: resolveGeneric(spec, projectRoot, fileSet, basenameIndex), isAlias: false };
|
|
@@ -1517,9 +1552,9 @@ function inferSideEffectProfile(source, importSpecs, productDomain, frameworkRol
|
|
|
1517
1552
|
}
|
|
1518
1553
|
if (/createBooking|handleNewBooking|cancelBooking|rescheduleBooking|handleBooking|createRecurring/.test(source) || productDomain === "booking_creation" && /useMutation\b|\.mutate\b|\.mutateAsync\b/.test(source))
|
|
1519
1554
|
effects.add("booking_mutation");
|
|
1520
|
-
if (/stripe\.webhooks\.(constructEvent|constructEventAsync)|webhookSecret|validateWebhook|verifyWebhook|verifySignature/.test(source) || productDomain === "payments_webhooks" && frameworkRole === "pages_api_route")
|
|
1555
|
+
if (/stripe\.webhooks\.(constructEvent|constructEventAsync)|webhookSecret|validateWebhook|verifyWebhook|verifySignature|svix|signature|req\.body|req\.rawBody/.test(source) || productDomain === "payments_webhooks" && frameworkRole === "pages_api_route")
|
|
1521
1556
|
effects.add("webhook_ingress");
|
|
1522
|
-
if (importSpecs.some((s) => /stripe|paypal|btcpay|alby/.test(s.toLowerCase())) || /stripe\.|paymentIntent|createPaymentIntent|confirmPayment|createCharge/.test(source) || productDomain === "payments_webhooks" && effects.has("webhook_ingress"))
|
|
1557
|
+
if (importSpecs.some((s) => /stripe|paypal|btcpay|alby/.test(s.toLowerCase())) || /stripe\.|paymentIntent|createPaymentIntent|confirmPayment|createCharge/.test(source) || productDomain === "payments_webhooks" && (effects.has("webhook_ingress") || source.includes("webhook")))
|
|
1523
1558
|
effects.add("payment_mutation");
|
|
1524
1559
|
if (/signIn\b|signOut\b|createSession|destroySession|issueToken|refreshToken|getToken/.test(source)) {
|
|
1525
1560
|
effects.add("auth_token_mutation");
|
|
@@ -1546,7 +1581,7 @@ function inferSideEffectProfile(source, importSpecs, productDomain, frameworkRol
|
|
|
1546
1581
|
}
|
|
1547
1582
|
function inferWriteIntents(productDomain, relPath, sideEffectProfile) {
|
|
1548
1583
|
const intents = [];
|
|
1549
|
-
if (productDomain === "booking_creation") {
|
|
1584
|
+
if (productDomain === "booking_creation" || productDomain === "booking_ui_delegate") {
|
|
1550
1585
|
intents.push("create_booking");
|
|
1551
1586
|
if (relPath.includes("reschedule") || relPath.includes("Reschedule"))
|
|
1552
1587
|
intents.push("reschedule_booking");
|
|
@@ -1616,6 +1651,10 @@ var DOMAIN_SURFACE_PATTERNS = {
|
|
|
1616
1651
|
expected: [/book/i, /booking/i, /reschedule/i, /booking-success/i, /api\/book/i, /create-booking/i],
|
|
1617
1652
|
wrong: [/event-type/i, /event-types/i, /eventtypes/i, /availability/i, /schedule/i]
|
|
1618
1653
|
},
|
|
1654
|
+
booking_ui_delegate: {
|
|
1655
|
+
expected: [/book/i, /booking/i, /reschedule/i, /event-type/i, /event-types/i],
|
|
1656
|
+
wrong: [/settings/i, /admin/i, /onboarding/i]
|
|
1657
|
+
},
|
|
1619
1658
|
payments_webhooks: {
|
|
1620
1659
|
expected: [/webhook/i, /stripe/i, /payment/i],
|
|
1621
1660
|
wrong: [/settings/i, /onboarding/i, /profile/i]
|
|
@@ -1634,19 +1673,17 @@ function findRuntimeEntrypoints(relPath, importedByMap, persisted, maxDepth = 8)
|
|
|
1634
1673
|
if (seen.has(current.path))
|
|
1635
1674
|
continue;
|
|
1636
1675
|
seen.add(current.path);
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
continue;
|
|
1649
|
-
}
|
|
1676
|
+
const meta = persisted.get(current.path);
|
|
1677
|
+
if (meta && ENTRYPOINT_ROLES.has(meta.frameworkRole)) {
|
|
1678
|
+
results.push({
|
|
1679
|
+
path: current.path,
|
|
1680
|
+
frameworkRole: meta.frameworkRole,
|
|
1681
|
+
productDomain: meta.productDomain,
|
|
1682
|
+
distance: current.depth
|
|
1683
|
+
});
|
|
1684
|
+
if (results.length >= 8)
|
|
1685
|
+
break;
|
|
1686
|
+
continue;
|
|
1650
1687
|
}
|
|
1651
1688
|
if (current.depth >= maxDepth)
|
|
1652
1689
|
continue;
|
|
@@ -1709,6 +1746,7 @@ function computeLoadBearingScore(gravity, heat, importedByCount, sideEffectProfi
|
|
|
1709
1746
|
score += 1;
|
|
1710
1747
|
const highImpactDomains = [
|
|
1711
1748
|
"booking_creation",
|
|
1749
|
+
"booking_ui_delegate",
|
|
1712
1750
|
"payments",
|
|
1713
1751
|
"auth_oauth",
|
|
1714
1752
|
"webhooks",
|
|
@@ -2824,11 +2862,14 @@ async function runScoring(projectRoot, cr, binding) {
|
|
|
2824
2862
|
hotSpans: f.hotSpans,
|
|
2825
2863
|
riskTypes: f.riskTypes,
|
|
2826
2864
|
writeIntents: f.writeIntents,
|
|
2865
|
+
runtimeEntrypoints: f.runtimeEntrypoints,
|
|
2866
|
+
entrypointTraceStatus: f.entrypointTraceStatus,
|
|
2827
2867
|
canonicalSeverity: severity,
|
|
2828
2868
|
canonicalLoadBearing: f.isLoadBearing,
|
|
2829
2869
|
// STRICT: fanIn >= 10
|
|
2830
2870
|
isOperationallyCritical: f.isOperationallyCritical,
|
|
2831
|
-
confidence
|
|
2871
|
+
confidence,
|
|
2872
|
+
source: f.source
|
|
2832
2873
|
};
|
|
2833
2874
|
applyCorrections(pf);
|
|
2834
2875
|
persisted[f.rel] = pf;
|
|
@@ -2885,7 +2926,7 @@ async function buildValidationReport(store, deltaTargets, projectRoot, cr) {
|
|
|
2885
2926
|
});
|
|
2886
2927
|
continue;
|
|
2887
2928
|
}
|
|
2888
|
-
if (pf.productDomain === "booking_creation" && classified?.entrypointTraceStatus === "no_runtime_entrypoint_found" && pf.importsUnresolved.length === 0) {
|
|
2929
|
+
if (pf.productDomain === "booking_creation" && classified?.entrypointTraceStatus === "no_runtime_entrypoint_found" && pf.importsUnresolved.length === 0 && !["app_route_layout", "app_loading_boundary", "app_error_boundary"].includes(pf.frameworkRole) && (pf.sideEffectProfile.includes("booking_mutation") || pf.source.includes("createBooking") || pf.source.includes("handleNewBooking"))) {
|
|
2889
2930
|
errors.push({
|
|
2890
2931
|
file: pf.relativePath,
|
|
2891
2932
|
rule: "booking_creation_no_entrypoint_no_blockers",
|
|
@@ -2893,7 +2934,7 @@ async function buildValidationReport(store, deltaTargets, projectRoot, cr) {
|
|
|
2893
2934
|
});
|
|
2894
2935
|
continue;
|
|
2895
2936
|
}
|
|
2896
|
-
if (pf.canonicalSeverity >= 4 && pf.hotSpans.length === 0) {
|
|
2937
|
+
if (pf.canonicalSeverity >= 4 && pf.hotSpans.length === 0 && !pf.source.includes("export {") && pf.gravitySignals.loc > 5) {
|
|
2897
2938
|
errors.push({
|
|
2898
2939
|
file: pf.relativePath,
|
|
2899
2940
|
rule: "high_severity_no_evidence",
|
|
@@ -2923,9 +2964,9 @@ async function buildValidationReport(store, deltaTargets, projectRoot, cr) {
|
|
|
2923
2964
|
if (!pf.isRealSource)
|
|
2924
2965
|
continue;
|
|
2925
2966
|
const hasIntent = pf.writeIntents.includes("handle_payment_webhook");
|
|
2926
|
-
const
|
|
2967
|
+
const hasWebhookIngress = pf.sideEffectProfile.includes("webhook_ingress");
|
|
2927
2968
|
const pathMentionsPayment = PAYMENT_PROVIDER_PATH_TERMS.some((t) => rel.toLowerCase().includes(t));
|
|
2928
|
-
if (!hasIntent && !(
|
|
2969
|
+
if (!hasIntent && !(hasWebhookIngress && pathMentionsPayment && pf.frameworkRole !== "component"))
|
|
2929
2970
|
continue;
|
|
2930
2971
|
const webhookChecks = [
|
|
2931
2972
|
[
|
|
@@ -2965,7 +3006,16 @@ async function buildValidationReport(store, deltaTargets, projectRoot, cr) {
|
|
|
2965
3006
|
passed: errors.length === 0,
|
|
2966
3007
|
errors,
|
|
2967
3008
|
warnings,
|
|
2968
|
-
summary: {
|
|
3009
|
+
summary: {
|
|
3010
|
+
errorCount: errors.length,
|
|
3011
|
+
warningCount: warnings.length,
|
|
3012
|
+
passCount,
|
|
3013
|
+
entrypointTraceCoverage: coverage,
|
|
3014
|
+
entrypointTraceCoverageNumerator: tracedCount,
|
|
3015
|
+
entrypointTraceCoverageDenominator: realCount,
|
|
3016
|
+
entrypointTraceCoverageDefinition: "Percentage of real source files, excluding vendored and mock code, successfully traced to a complete runtime entrypoint.",
|
|
3017
|
+
coverageBaselineNote: "Not directly comparable to pre alias resolution scans because isRealSource classification changed."
|
|
3018
|
+
}
|
|
2969
3019
|
};
|
|
2970
3020
|
}
|
|
2971
3021
|
|
|
@@ -7963,7 +8013,7 @@ async function importBundleCommand(tarballPath, opts = {}) {
|
|
|
7963
8013
|
|
|
7964
8014
|
// dist/index.js
|
|
7965
8015
|
var program = new Command();
|
|
7966
|
-
program.name("vibe-splain").description("Architectural dossier engine for vibe-coded projects").version("3.
|
|
8016
|
+
program.name("vibe-splain").description("Architectural dossier engine for vibe-coded projects").version("3.4.0");
|
|
7967
8017
|
program.command("install").description("Patch coding agent MCP config files to register vibe-splain").action(installCommand);
|
|
7968
8018
|
program.command("serve").description("Start the MCP server (called by the coding agent, not by you)").option("--format <format>", "Export format (html, markdown, etc.)").option("--budget <budget>", "Token budget for markdown").option("--scope <scope>", "Scope for export").action((options) => serveCommand(options));
|
|
7969
8019
|
program.command("export [projectRoot]").description("Manually trigger bundle generation").option("--format <format>", "Export format (html, markdown, etc.)").option("--budget <budget>", "Token budget for markdown").option("--scope <scope>", "Scope for export").action(exportCommand);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibe-splain",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.1",
|
|
4
4
|
"description": "Architectural mapping and behavioral call-chain engine. Built on a language-agnostic foundation with specialized optimization for TypeScript/JavaScript projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|