vibe-splain 3.3.1 → 3.4.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 +34 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1043,7 +1043,17 @@ function analyzeAst(source, lang, tree) {
|
|
|
1043
1043
|
for (const fn of fnNodes) {
|
|
1044
1044
|
const bodyLOC = nodeLOC(fn);
|
|
1045
1045
|
const decisions = countDecisions(fn);
|
|
1046
|
-
|
|
1046
|
+
let score = decisions + bodyLOC;
|
|
1047
|
+
const text = fn.text;
|
|
1048
|
+
if (lang === "typescript" || lang === "tsx" || lang === "javascript") {
|
|
1049
|
+
if (/stripe|webhook|payload|signature|event/i.test(text) && /switch|case|if/i.test(text)) {
|
|
1050
|
+
score += 25;
|
|
1051
|
+
}
|
|
1052
|
+
if (text.includes("prisma") && (text.includes("create") || text.includes("update"))) {
|
|
1053
|
+
score += 10;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
scored.push({ node: fn, decisions, bodyLOC, score });
|
|
1047
1057
|
if (bodyLOC > LONG_FN_LOC) {
|
|
1048
1058
|
longFunctions++;
|
|
1049
1059
|
smells.push({
|
|
@@ -1073,7 +1083,7 @@ function analyzeAst(source, lang, tree) {
|
|
|
1073
1083
|
});
|
|
1074
1084
|
}
|
|
1075
1085
|
scored.sort((a, b) => b.score - a.score);
|
|
1076
|
-
const hotSpans = scored.slice(0, 3).filter((s) => s.bodyLOC >=
|
|
1086
|
+
const hotSpans = scored.slice(0, 3).filter((s) => s.bodyLOC >= 2).map((s) => {
|
|
1077
1087
|
const rawExcerpt = source.split("\n").slice(s.node.startPosition.row, s.node.endPosition.row + 1).join("\n");
|
|
1078
1088
|
const snippet = stripLeadingComments(rawExcerpt).slice(0, 2e3);
|
|
1079
1089
|
return {
|
|
@@ -1517,9 +1527,9 @@ function inferSideEffectProfile(source, importSpecs, productDomain, frameworkRol
|
|
|
1517
1527
|
}
|
|
1518
1528
|
if (/createBooking|handleNewBooking|cancelBooking|rescheduleBooking|handleBooking|createRecurring/.test(source) || productDomain === "booking_creation" && /useMutation\b|\.mutate\b|\.mutateAsync\b/.test(source))
|
|
1519
1529
|
effects.add("booking_mutation");
|
|
1520
|
-
if (/stripe\.webhooks\.(constructEvent|constructEventAsync)|webhookSecret|validateWebhook|verifyWebhook|verifySignature/.test(source) || productDomain === "payments_webhooks" && frameworkRole === "pages_api_route")
|
|
1530
|
+
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
1531
|
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"))
|
|
1532
|
+
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
1533
|
effects.add("payment_mutation");
|
|
1524
1534
|
if (/signIn\b|signOut\b|createSession|destroySession|issueToken|refreshToken|getToken/.test(source)) {
|
|
1525
1535
|
effects.add("auth_token_mutation");
|
|
@@ -1634,19 +1644,17 @@ function findRuntimeEntrypoints(relPath, importedByMap, persisted, maxDepth = 8)
|
|
|
1634
1644
|
if (seen.has(current.path))
|
|
1635
1645
|
continue;
|
|
1636
1646
|
seen.add(current.path);
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
continue;
|
|
1649
|
-
}
|
|
1647
|
+
const meta = persisted.get(current.path);
|
|
1648
|
+
if (meta && ENTRYPOINT_ROLES.has(meta.frameworkRole)) {
|
|
1649
|
+
results.push({
|
|
1650
|
+
path: current.path,
|
|
1651
|
+
frameworkRole: meta.frameworkRole,
|
|
1652
|
+
productDomain: meta.productDomain,
|
|
1653
|
+
distance: current.depth
|
|
1654
|
+
});
|
|
1655
|
+
if (results.length >= 8)
|
|
1656
|
+
break;
|
|
1657
|
+
continue;
|
|
1650
1658
|
}
|
|
1651
1659
|
if (current.depth >= maxDepth)
|
|
1652
1660
|
continue;
|
|
@@ -2824,11 +2832,14 @@ async function runScoring(projectRoot, cr, binding) {
|
|
|
2824
2832
|
hotSpans: f.hotSpans,
|
|
2825
2833
|
riskTypes: f.riskTypes,
|
|
2826
2834
|
writeIntents: f.writeIntents,
|
|
2835
|
+
runtimeEntrypoints: f.runtimeEntrypoints,
|
|
2836
|
+
entrypointTraceStatus: f.entrypointTraceStatus,
|
|
2827
2837
|
canonicalSeverity: severity,
|
|
2828
2838
|
canonicalLoadBearing: f.isLoadBearing,
|
|
2829
2839
|
// STRICT: fanIn >= 10
|
|
2830
2840
|
isOperationallyCritical: f.isOperationallyCritical,
|
|
2831
|
-
confidence
|
|
2841
|
+
confidence,
|
|
2842
|
+
source: f.source
|
|
2832
2843
|
};
|
|
2833
2844
|
applyCorrections(pf);
|
|
2834
2845
|
persisted[f.rel] = pf;
|
|
@@ -2885,7 +2896,7 @@ async function buildValidationReport(store, deltaTargets, projectRoot, cr) {
|
|
|
2885
2896
|
});
|
|
2886
2897
|
continue;
|
|
2887
2898
|
}
|
|
2888
|
-
if (pf.productDomain === "booking_creation" && classified?.entrypointTraceStatus === "no_runtime_entrypoint_found" && pf.importsUnresolved.length === 0) {
|
|
2899
|
+
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
2900
|
errors.push({
|
|
2890
2901
|
file: pf.relativePath,
|
|
2891
2902
|
rule: "booking_creation_no_entrypoint_no_blockers",
|
|
@@ -2893,7 +2904,7 @@ async function buildValidationReport(store, deltaTargets, projectRoot, cr) {
|
|
|
2893
2904
|
});
|
|
2894
2905
|
continue;
|
|
2895
2906
|
}
|
|
2896
|
-
if (pf.canonicalSeverity >= 4 && pf.hotSpans.length === 0) {
|
|
2907
|
+
if (pf.canonicalSeverity >= 4 && pf.hotSpans.length === 0 && !pf.source.includes("export {") && pf.gravitySignals.loc > 5) {
|
|
2897
2908
|
errors.push({
|
|
2898
2909
|
file: pf.relativePath,
|
|
2899
2910
|
rule: "high_severity_no_evidence",
|
|
@@ -2923,9 +2934,9 @@ async function buildValidationReport(store, deltaTargets, projectRoot, cr) {
|
|
|
2923
2934
|
if (!pf.isRealSource)
|
|
2924
2935
|
continue;
|
|
2925
2936
|
const hasIntent = pf.writeIntents.includes("handle_payment_webhook");
|
|
2926
|
-
const
|
|
2937
|
+
const hasWebhookIngress = pf.sideEffectProfile.includes("webhook_ingress");
|
|
2927
2938
|
const pathMentionsPayment = PAYMENT_PROVIDER_PATH_TERMS.some((t) => rel.toLowerCase().includes(t));
|
|
2928
|
-
if (!hasIntent && !(
|
|
2939
|
+
if (!hasIntent && !(hasWebhookIngress && pathMentionsPayment && pf.frameworkRole !== "component"))
|
|
2929
2940
|
continue;
|
|
2930
2941
|
const webhookChecks = [
|
|
2931
2942
|
[
|
|
@@ -7963,7 +7974,7 @@ async function importBundleCommand(tarballPath, opts = {}) {
|
|
|
7963
7974
|
|
|
7964
7975
|
// dist/index.js
|
|
7965
7976
|
var program = new Command();
|
|
7966
|
-
program.name("vibe-splain").description("Architectural dossier engine for vibe-coded projects").version("3.
|
|
7977
|
+
program.name("vibe-splain").description("Architectural dossier engine for vibe-coded projects").version("3.4.0");
|
|
7967
7978
|
program.command("install").description("Patch coding agent MCP config files to register vibe-splain").action(installCommand);
|
|
7968
7979
|
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
7980
|
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.0",
|
|
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",
|