@nqminds/mcp-client 1.0.30 → 1.0.31

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.
@@ -1 +1 @@
1
- {"version":3,"file":"MCPChat.d.ts","sourceRoot":"","sources":["../src/MCPChat.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAIxE,OAAO,KAAK,EAAyB,YAAY,EAAe,MAAM,SAAS,CAAC;AAwahF,wBAAgB,OAAO,CAAC,EACtB,aAAa,EACb,WAA6B,EAC7B,YAAiB,EACjB,SAAc,GACf,EAAE,YAAY,qBA6hBd"}
1
+ {"version":3,"file":"MCPChat.d.ts","sourceRoot":"","sources":["../src/MCPChat.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAIxE,OAAO,KAAK,EAAyB,YAAY,EAAe,MAAM,SAAS,CAAC;AAgchF,wBAAgB,OAAO,CAAC,EACtB,aAAa,EACb,WAA6B,EAC7B,YAAiB,EACjB,SAAc,GACf,EAAE,YAAY,qBA6hBd"}
package/dist/MCPChat.js CHANGED
@@ -12,80 +12,97 @@ function stripUtmSource(url) {
12
12
  .replace(/\?$/, "");
13
13
  }
14
14
  /**
15
- * Fixes broken markdown tables where row-separating newlines are missing.
16
- * Detects the separator row (|---|---|) to infer column count, then uses
17
- * pipe-counting to split the flattened table text back into proper rows.
15
+ * Fixes broken markdown tables produced by streaming LLM output.
16
+ *
17
+ * The LLM often emits an entire table (title + header + separator + data rows)
18
+ * as a single line, e.g.:
19
+ * "My title | Col A | Col B | |---|---| | val1 | val2 | | val3 | val4 |"
20
+ *
21
+ * Strategy:
22
+ * 1. Split content into lines.
23
+ * 2. For each line, detect whether a markdown separator pattern
24
+ * (|---|---| etc.) appears *somewhere* but the line is NOT already a
25
+ * standalone separator or a normal single table row.
26
+ * 3. If so, extract any leading title text, then split the remainder into
27
+ * individual pipe-delimited rows by counting pipes.
28
+ * 4. Emit blank + title (if any) + one row per line + blank.
29
+ *
30
+ * Deliberately avoids touching `preprocessLinks` output (markdown links
31
+ * have the form `[text](url)` which contains no `|`, so they are safe).
18
32
  */
19
33
  function fixBrokenTables(content) {
20
- // 1) Rejoin separator rows that were split across line breaks
21
- // e.g. "|---|---\n:|---|" → "|---|---:|---|"
22
- content = content.replace(/(\|[-:| ]*-)[ \t]*\r?\n[ \t]*([-:| ]*\|)/g, (full, p1, p2) => {
23
- const joined = p1 + p2;
24
- if (/^\|[ :]*-{2,}[ :]*(\|[ :]*-{2,}[ :]*)+\|$/.test(joined.trim()))
25
- return joined;
26
- return full;
27
- });
28
- // 2) Scan line-by-line for inline separator patterns (= broken table)
29
- const SEP_RE = /\|[ :]*-{2,}[ :]*(?:\|[ :]*-{2,}[ :]*)+\|/;
34
+ const SEP_CELL = /^[ \t]*:?-{2,}:?[ \t]*$/;
35
+ // Matches a run of pipe-delimited separator cells: |---|---:|:---|
36
+ const SEP_RE = /\|[ \t]*:?-{2,}:?[ \t]*(?:\|[ \t]*:?-{2,}:?[ \t]*)+\|/;
30
37
  const lines = content.split("\n");
31
38
  const out = [];
32
- let i = 0;
33
- while (i < lines.length) {
39
+ for (let i = 0; i < lines.length; i++) {
34
40
  const line = lines[i];
35
- const sepMatch = line.match(SEP_RE);
36
- // No separator on this line, or the line IS just the separator → fine
37
- if (!sepMatch || line.trim() === sepMatch[0]) {
41
+ // Find a separator sub-string in this line
42
+ const sepMatch = SEP_RE.exec(line);
43
+ if (!sepMatch) {
38
44
  out.push(line);
39
- i++;
40
45
  continue;
41
46
  }
42
- // Broken table: separator is inline with other content
43
- const sep = sepMatch[0];
44
- const cols = sep.split("|").filter((s) => /^[ :]*-+[ :]*$/.test(s)).length;
45
- if (cols < 2) {
47
+ const sepStr = sepMatch[0];
48
+ // Count columns from the separator
49
+ const cols = sepStr.split("|").filter((s) => SEP_CELL.test(s)).length;
50
+ if (cols < 1) {
46
51
  out.push(line);
47
- i++;
48
52
  continue;
49
53
  }
50
- // Absorb continuation lines that look like table content (start with |)
51
- let raw = line;
52
- i++;
53
- while (i < lines.length) {
54
- const next = lines[i].trim();
55
- if (!next || !next.startsWith("|"))
56
- break;
57
- raw += " " + next;
58
- i++;
54
+ // If the line is ONLY the separator (possibly with surrounding whitespace)
55
+ // it's already correct — leave it alone.
56
+ if (line.trim() === sepStr.trim()) {
57
+ out.push(line);
58
+ continue;
59
59
  }
60
- // Flatten whitespace and locate every unescaped pipe
61
- const flat = raw.replace(/\s+/g, " ").trim();
62
- const pipes = [];
63
- for (let k = 0; k < flat.length; k++) {
64
- if (flat[k] === "|" && (k === 0 || flat[k - 1] !== "\\"))
65
- pipes.push(k);
60
+ // There may be a title/description before the first pipe.
61
+ // Everything before the very first "|" in the line is the title.
62
+ const firstPipeIdx = line.indexOf("|");
63
+ const title = firstPipeIdx > 0 ? line.substring(0, firstPipeIdx).trim() : "";
64
+ // Table content is everything from the first "|" onwards.
65
+ const tableText = firstPipeIdx >= 0 ? line.substring(firstPipeIdx) : line;
66
+ // Split into individual cells by pipe, preserving the "|" delimiters.
67
+ // We walk character-by-character and emit a new row every time we have
68
+ // accumulated exactly (cols + 1) pipe characters.
69
+ const rows = [];
70
+ let currentRow = "";
71
+ let pipeCount = 0;
72
+ const perRow = cols + 1; // a N-column row has N+1 pipes
73
+ for (let k = 0; k < tableText.length; k++) {
74
+ const ch = tableText[k];
75
+ currentRow += ch;
76
+ if (ch === "|") {
77
+ pipeCount++;
78
+ if (pipeCount === perRow) {
79
+ rows.push(currentRow.trim());
80
+ currentRow = "";
81
+ pipeCount = 0;
82
+ // Skip any whitespace between rows
83
+ while (k + 1 < tableText.length && tableText[k + 1] === " ")
84
+ k++;
85
+ }
86
+ }
66
87
  }
67
- const perRow = cols + 1; // pipes per table row
68
- const fullRows = Math.floor(pipes.length / perRow);
69
- if (fullRows < 2) {
70
- out.push(raw);
88
+ // Any leftover (incomplete row happens during streaming)
89
+ if (currentRow.trim())
90
+ rows.push(currentRow.trim());
91
+ // Need at least header + separator to bother reconstructing
92
+ if (rows.length < 2) {
93
+ out.push(line);
71
94
  continue;
72
- } // can't reconstruct
73
- // Text that precedes the first pipe (e.g. a heading label)
74
- const prefix = flat.substring(0, pipes[0]).trim();
75
- if (prefix) {
76
- out.push(prefix);
77
- out.push("");
78
95
  }
79
- // Emit each complete row on its own line
80
- for (let r = 0; r < fullRows; r++) {
81
- out.push(flat.substring(pipes[r * perRow], pipes[r * perRow + perRow - 1] + 1));
82
- }
83
- // Trailing text after last complete row
84
- const trailing = flat.substring(pipes[fullRows * perRow - 1] + 1).trim();
85
- if (trailing) {
96
+ // Emit: blank line, optional title, then each row on its own line, blank line
97
+ if (out.length > 0 && out[out.length - 1] !== "")
98
+ out.push("");
99
+ if (title) {
100
+ out.push(title);
86
101
  out.push("");
87
- out.push(trailing);
88
102
  }
103
+ for (const row of rows)
104
+ out.push(row);
105
+ out.push("");
89
106
  }
90
107
  return out.join("\n");
91
108
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nqminds/mcp-client",
3
- "version": "1.0.30",
3
+ "version": "1.0.31",
4
4
  "description": "Reusable MCP client component with AI chat interface",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",