vibe-splain 2.0.2 → 2.0.3

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 CHANGED
@@ -1508,6 +1508,13 @@ import { createHash as createHash2 } from "crypto";
1508
1508
  import { readFile as readFile8 } from "fs/promises";
1509
1509
  import { join as join7 } from "path";
1510
1510
  var CATEGORIES = ["Bottleneck", "Hack", "Smart-Move", "Risk", "Convention", "Dead-Weight"];
1511
+ function normalizeSnippet(s) {
1512
+ let out = (s ?? "").replace(/\r\n/g, "\n");
1513
+ if (/\\[nt]/.test(out)) {
1514
+ out = out.replace(/\\r\\n/g, "\n").replace(/\\n/g, "\n").replace(/\\t/g, " ");
1515
+ }
1516
+ return out.split("\n").map((l) => l.replace(/\s+$/, "")).join("\n").replace(/^\n+|\n+$/g, "");
1517
+ }
1511
1518
  var writeDecisionCardTool = {
1512
1519
  name: "write_decision_card",
1513
1520
  description: "Persists ONE Decision Card about ONE file. This is a hostile architecture review, not documentation. The thesis must be a VERDICT, not a description. The pillar MUST be one of the names from get_project_map (free-form is rejected). One card per file (duplicates rejected). Evidence must come from get_file_context hotSpans/smellSpans \u2014 never the header comment, never the whole file.",
@@ -1556,9 +1563,10 @@ async function handleWriteDecisionCard(args) {
1556
1563
  const tradeoff = args.tradeoff || null;
1557
1564
  const blastRadius = args.blastRadius || null;
1558
1565
  const confidence = args.confidence || "medium";
1559
- const evidence = args.evidence;
1566
+ const rawEvidence = args.evidence;
1567
+ const evidence = (rawEvidence || []).map((e) => ({ ...e, snippet: normalizeSnippet(e.snippet) }));
1560
1568
  const diagram = args.diagram || null;
1561
- if (!projectRoot || !pillar || !primaryFile || !title || !thesis || !category || !narrative || !evidence) {
1569
+ if (!projectRoot || !pillar || !primaryFile || !title || !thesis || !category || !narrative || !rawEvidence || rawEvidence.length === 0) {
1562
1570
  throw new Error("projectRoot, pillar, primaryFile, title, thesis, category, narrative, and evidence are required");
1563
1571
  }
1564
1572
  if (!CATEGORIES.includes(category)) {
@@ -4,6 +4,15 @@ import { createHash } from 'crypto';
4
4
  import { readFile } from 'fs/promises';
5
5
  import { join } from 'path';
6
6
  const CATEGORIES = ['Bottleneck', 'Hack', 'Smart-Move', 'Risk', 'Convention', 'Dead-Weight'];
7
+ // Agents frequently emit snippets with literal "\n"/"\t" instead of real
8
+ // newlines, which collapses the code into one line in the UI. Restore them.
9
+ function normalizeSnippet(s) {
10
+ let out = (s ?? '').replace(/\r\n/g, '\n');
11
+ if (/\\[nt]/.test(out)) {
12
+ out = out.replace(/\\r\\n/g, '\n').replace(/\\n/g, '\n').replace(/\\t/g, ' ');
13
+ }
14
+ return out.split('\n').map(l => l.replace(/\s+$/, '')).join('\n').replace(/^\n+|\n+$/g, '');
15
+ }
7
16
  export const writeDecisionCardTool = {
8
17
  name: 'write_decision_card',
9
18
  description: 'Persists ONE Decision Card about ONE file. This is a hostile architecture review, not documentation. The thesis must be a VERDICT, not a description. The pillar MUST be one of the names from get_project_map (free-form is rejected). One card per file (duplicates rejected). Evidence must come from get_file_context hotSpans/smellSpans — never the header comment, never the whole file.',
@@ -52,9 +61,10 @@ export async function handleWriteDecisionCard(args) {
52
61
  const tradeoff = args.tradeoff || null;
53
62
  const blastRadius = args.blastRadius || null;
54
63
  const confidence = args.confidence || 'medium';
55
- const evidence = args.evidence;
64
+ const rawEvidence = args.evidence;
65
+ const evidence = (rawEvidence || []).map(e => ({ ...e, snippet: normalizeSnippet(e.snippet) }));
56
66
  const diagram = args.diagram || null;
57
- if (!projectRoot || !pillar || !primaryFile || !title || !thesis || !category || !narrative || !evidence) {
67
+ if (!projectRoot || !pillar || !primaryFile || !title || !thesis || !category || !narrative || !rawEvidence || rawEvidence.length === 0) {
58
68
  throw new Error('projectRoot, pillar, primaryFile, title, thesis, category, narrative, and evidence are required');
59
69
  }
60
70
  if (!CATEGORIES.includes(category)) {