@verygoodplugins/mcp-freescout 1.1.1 → 1.1.2
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/.claude/settings.local.json +2 -1
- package/README.md +9 -3
- package/dist/freescout-api.d.ts.map +1 -1
- package/dist/freescout-api.js +62 -23
- package/dist/freescout-api.js.map +1 -1
- package/package.json +1 -1
- package/test-markdown.js +150 -0
package/README.md
CHANGED
|
@@ -143,7 +143,9 @@ Fetch a FreeScout ticket with all its details and conversation threads.
|
|
|
143
143
|
}
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
-
|
|
146
|
+
**Example: Fetching a FreeScout ticket with conversation threads**
|
|
147
|
+
|
|
148
|
+

|
|
147
149
|
|
|
148
150
|
|
|
149
151
|
#### `freescout_analyze_ticket`
|
|
@@ -160,7 +162,9 @@ Analyze a ticket to determine issue type, root cause, and suggested solutions.
|
|
|
160
162
|
- Root cause analysis
|
|
161
163
|
- Bug vs feature request vs third-party issue determination
|
|
162
164
|
|
|
163
|
-
|
|
165
|
+
**Example: Intelligent ticket analysis with issue classification**
|
|
166
|
+
|
|
167
|
+

|
|
164
168
|
|
|
165
169
|
#### `freescout_add_note`
|
|
166
170
|
Add an internal note to a ticket for team communication.
|
|
@@ -200,7 +204,9 @@ Create a draft reply in FreeScout that can be edited before sending. This tool l
|
|
|
200
204
|
3. Use `freescout_create_draft_reply` to save the draft in FreeScout (Markdown automatically converted to HTML)
|
|
201
205
|
4. Review and edit the draft in FreeScout before sending
|
|
202
206
|
|
|
203
|
-
|
|
207
|
+
**Example: Draft reply workflow with personalized customer response**
|
|
208
|
+
|
|
209
|
+

|
|
204
210
|
|
|
205
211
|
#### `freescout_get_ticket_context`
|
|
206
212
|
Get ticket context and customer information to help craft personalized replies.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"freescout-api.d.ts","sourceRoot":"","sources":["../src/freescout-api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAK3C;;OAEG;IACH,OAAO,CAAC,cAAc;
|
|
1
|
+
{"version":3,"file":"freescout-api.d.ts","sourceRoot":"","sources":["../src/freescout-api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAK3C;;OAEG;IACH,OAAO,CAAC,cAAc;YAgIR,OAAO;IA6Bf,eAAe,CACnB,QAAQ,EAAE,MAAM,EAChB,cAAc,GAAE,OAAc,GAC7B,OAAO,CAAC,qBAAqB,CAAC;IAO3B,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,EACrC,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,OAAO,GAAG,WAAW,GAC5B,OAAO,CAAC,eAAe,CAAC;IAqBrB,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,eAAe,CAAC;IAMrB,kBAAkB,CACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;QACP,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;QAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GACA,OAAO,CAAC,qBAAqB,CAAC;IAQ3B,mBAAmB,CACvB,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,oBAAoB,CAAC,qBAAqB,CAAC,CAAC;IAUvD,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAQlD,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;CAoBxC"}
|
package/dist/freescout-api.js
CHANGED
|
@@ -10,24 +10,61 @@ export class FreeScoutAPI {
|
|
|
10
10
|
* Convert Markdown formatting to HTML for FreeScout
|
|
11
11
|
*/
|
|
12
12
|
markdownToHtml(text) {
|
|
13
|
-
let html = text;
|
|
14
13
|
// Convert bold text: **text** or __text__ -> <strong>text</strong>
|
|
15
|
-
html =
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
let html = text
|
|
15
|
+
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
|
16
|
+
.replace(/__(.*?)__/g, '<strong>$1</strong>');
|
|
17
|
+
// Convert italic text: *text* or _text_ -> <em>text</em> (avoid conflicts with bold)
|
|
18
18
|
html = html.replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, '<em>$1</em>');
|
|
19
19
|
html = html.replace(/(?<!_)_([^_]+)_(?!_)/g, '<em>$1</em>');
|
|
20
20
|
// Convert code: `text` -> <code>text</code>
|
|
21
21
|
html = html.replace(/`(.*?)`/g, '<code>$1</code>');
|
|
22
|
-
//
|
|
22
|
+
// Process the entire text to handle lists that span paragraph breaks
|
|
23
23
|
const lines = html.split('\n');
|
|
24
24
|
const processedLines = [];
|
|
25
25
|
let inOrderedList = false;
|
|
26
26
|
let inUnorderedList = false;
|
|
27
|
+
let currentParagraph = [];
|
|
27
28
|
for (let i = 0; i < lines.length; i++) {
|
|
28
|
-
const line = lines[i]
|
|
29
|
+
const line = lines[i];
|
|
30
|
+
const trimmedLine = line.trim();
|
|
31
|
+
// Check for empty lines (paragraph breaks)
|
|
32
|
+
if (!trimmedLine) {
|
|
33
|
+
// Check if the next non-empty line is also a list item
|
|
34
|
+
const nextListItemIndex = lines.slice(i + 1).findIndex(nextLine => {
|
|
35
|
+
const nextTrimmed = nextLine.trim();
|
|
36
|
+
return nextTrimmed && (/^\d+\.\s+/.test(nextTrimmed) || /^[-*]\s+/.test(nextTrimmed));
|
|
37
|
+
});
|
|
38
|
+
// If we're in a list and the next item is also a list item, continue the list
|
|
39
|
+
if ((inOrderedList || inUnorderedList) && nextListItemIndex !== -1) {
|
|
40
|
+
continue; // Skip this empty line but keep the list open
|
|
41
|
+
}
|
|
42
|
+
// Close any current lists before starting new paragraph
|
|
43
|
+
if (inOrderedList) {
|
|
44
|
+
processedLines.push('</ol>');
|
|
45
|
+
inOrderedList = false;
|
|
46
|
+
}
|
|
47
|
+
if (inUnorderedList) {
|
|
48
|
+
processedLines.push('</ul>');
|
|
49
|
+
inUnorderedList = false;
|
|
50
|
+
}
|
|
51
|
+
// Process accumulated paragraph
|
|
52
|
+
if (currentParagraph.length > 0) {
|
|
53
|
+
const paragraphContent = currentParagraph.join('<br>');
|
|
54
|
+
processedLines.push(`<p>${paragraphContent}</p>`);
|
|
55
|
+
currentParagraph = [];
|
|
56
|
+
}
|
|
57
|
+
// Skip extra empty lines
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
29
60
|
// Check for numbered list items
|
|
30
|
-
if (/^\d+\.\s+/.test(
|
|
61
|
+
if (/^\d+\.\s+/.test(trimmedLine)) {
|
|
62
|
+
// Finish any current paragraph
|
|
63
|
+
if (currentParagraph.length > 0) {
|
|
64
|
+
const paragraphContent = currentParagraph.join('<br>');
|
|
65
|
+
processedLines.push(`<p>${paragraphContent}</p>`);
|
|
66
|
+
currentParagraph = [];
|
|
67
|
+
}
|
|
31
68
|
if (!inOrderedList) {
|
|
32
69
|
if (inUnorderedList) {
|
|
33
70
|
processedLines.push('</ul>');
|
|
@@ -36,11 +73,17 @@ export class FreeScoutAPI {
|
|
|
36
73
|
processedLines.push('<ol>');
|
|
37
74
|
inOrderedList = true;
|
|
38
75
|
}
|
|
39
|
-
const content =
|
|
76
|
+
const content = trimmedLine.replace(/^\d+\.\s+/, '');
|
|
40
77
|
processedLines.push(`<li>${content}</li>`);
|
|
41
78
|
}
|
|
42
79
|
// Check for bullet list items
|
|
43
|
-
else if (/^[-*]\s+/.test(
|
|
80
|
+
else if (/^[-*]\s+/.test(trimmedLine)) {
|
|
81
|
+
// Finish any current paragraph
|
|
82
|
+
if (currentParagraph.length > 0) {
|
|
83
|
+
const paragraphContent = currentParagraph.join('<br>');
|
|
84
|
+
processedLines.push(`<p>${paragraphContent}</p>`);
|
|
85
|
+
currentParagraph = [];
|
|
86
|
+
}
|
|
44
87
|
if (!inUnorderedList) {
|
|
45
88
|
if (inOrderedList) {
|
|
46
89
|
processedLines.push('</ol>');
|
|
@@ -49,11 +92,12 @@ export class FreeScoutAPI {
|
|
|
49
92
|
processedLines.push('<ul>');
|
|
50
93
|
inUnorderedList = true;
|
|
51
94
|
}
|
|
52
|
-
const content =
|
|
95
|
+
const content = trimmedLine.replace(/^[-*]\s+/, '');
|
|
53
96
|
processedLines.push(`<li>${content}</li>`);
|
|
54
97
|
}
|
|
55
98
|
// Regular line
|
|
56
99
|
else {
|
|
100
|
+
// Close any lists
|
|
57
101
|
if (inOrderedList) {
|
|
58
102
|
processedLines.push('</ol>');
|
|
59
103
|
inOrderedList = false;
|
|
@@ -62,7 +106,8 @@ export class FreeScoutAPI {
|
|
|
62
106
|
processedLines.push('</ul>');
|
|
63
107
|
inUnorderedList = false;
|
|
64
108
|
}
|
|
65
|
-
|
|
109
|
+
// Add to current paragraph
|
|
110
|
+
currentParagraph.push(trimmedLine);
|
|
66
111
|
}
|
|
67
112
|
}
|
|
68
113
|
// Close any remaining lists
|
|
@@ -70,18 +115,12 @@ export class FreeScoutAPI {
|
|
|
70
115
|
processedLines.push('</ol>');
|
|
71
116
|
if (inUnorderedList)
|
|
72
117
|
processedLines.push('</ul>');
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
.replace(/(?<!<\/li>)$/gm, '</p>');
|
|
80
|
-
// Clean up paragraph tags around lists
|
|
81
|
-
html = html.replace(/<p>(<[uo]l>)/g, '$1');
|
|
82
|
-
html = html.replace(/(<\/[uo]l>)<\/p>/g, '$1');
|
|
83
|
-
html = html.replace(/<p><\/p>/g, '');
|
|
84
|
-
return html;
|
|
118
|
+
// Process any remaining paragraph
|
|
119
|
+
if (currentParagraph.length > 0) {
|
|
120
|
+
const paragraphContent = currentParagraph.join('<br>');
|
|
121
|
+
processedLines.push(`<p>${paragraphContent}</p>`);
|
|
122
|
+
}
|
|
123
|
+
return processedLines.join('\n\n');
|
|
85
124
|
}
|
|
86
125
|
async request(path, method = 'GET', body) {
|
|
87
126
|
const url = `${this.baseUrl}/api${path}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"freescout-api.js","sourceRoot":"","sources":["../src/freescout-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;AAO/B,MAAM,OAAO,YAAY;IACf,OAAO,CAAS;IAChB,MAAM,CAAS;IAEvB,YAAY,OAAe,EAAE,MAAc;QACzC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,wBAAwB;QACnE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,IAAY;QACjC,
|
|
1
|
+
{"version":3,"file":"freescout-api.js","sourceRoot":"","sources":["../src/freescout-api.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/test-markdown.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Quick test of the markdown converter
|
|
2
|
+
const testInput = `Hi Victor,
|
|
3
|
+
|
|
4
|
+
Thanks for helping us identify this issue! Based on your experience with the EngageBay LiveChat plugin conflict, we've implemented a solution to prevent this confusion for future users.
|
|
5
|
+
|
|
6
|
+
**What we've added:**
|
|
7
|
+
|
|
8
|
+
1. **Proactive Warning System** - When users have conflicting plugins installed (like EngageBay LiveChat, LeadConnector, or GHL Connect), WP Fusion will now display a warning message before they attempt OAuth authorization, letting them know these plugins may interfere with the connection process.
|
|
9
|
+
|
|
10
|
+
2. **Enhanced Error Messages** - If the \`invalid_grant\` error does occur, users will now receive specific guidance about potential plugin conflicts rather than the cryptic error message you experienced.
|
|
11
|
+
|
|
12
|
+
This improvement will be included in the next WP Fusion update and should help other users avoid the frustration you encountered. The system will specifically detect the EngageBay LiveChat plugin (and others we discover) and provide clear guidance on temporarily disabling them during the OAuth setup process.
|
|
13
|
+
|
|
14
|
+
Thanks again for your patience in working through this issue and helping us identify the root cause. Your feedback directly led to this improvement that will benefit all WP Fusion users integrating with HighLevel!
|
|
15
|
+
|
|
16
|
+
Best regards,
|
|
17
|
+
Jack`;
|
|
18
|
+
|
|
19
|
+
function markdownToHtml(text) {
|
|
20
|
+
// Convert bold text: **text** or __text__ -> <strong>text</strong>
|
|
21
|
+
let html = text
|
|
22
|
+
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
|
23
|
+
.replace(/__(.*?)__/g, '<strong>$1</strong>');
|
|
24
|
+
|
|
25
|
+
// Convert italic text: *text* or _text_ -> <em>text</em> (avoid conflicts with bold)
|
|
26
|
+
html = html.replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, '<em>$1</em>');
|
|
27
|
+
html = html.replace(/(?<!_)_([^_]+)_(?!_)/g, '<em>$1</em>');
|
|
28
|
+
|
|
29
|
+
// Convert code: `text` -> <code>text</code>
|
|
30
|
+
html = html.replace(/`(.*?)`/g, '<code>$1</code>');
|
|
31
|
+
|
|
32
|
+
// Process the entire text to handle lists that span paragraph breaks
|
|
33
|
+
const lines = html.split('\n');
|
|
34
|
+
const processedLines = [];
|
|
35
|
+
let inOrderedList = false;
|
|
36
|
+
let inUnorderedList = false;
|
|
37
|
+
let currentParagraph = [];
|
|
38
|
+
|
|
39
|
+
for (let i = 0; i < lines.length; i++) {
|
|
40
|
+
const line = lines[i];
|
|
41
|
+
const trimmedLine = line.trim();
|
|
42
|
+
|
|
43
|
+
// Check for empty lines (paragraph breaks)
|
|
44
|
+
if (!trimmedLine) {
|
|
45
|
+
// Check if the next non-empty line is also a list item
|
|
46
|
+
const nextListItemIndex = lines.slice(i + 1).findIndex(nextLine => {
|
|
47
|
+
const nextTrimmed = nextLine.trim();
|
|
48
|
+
return nextTrimmed && (/^\d+\.\s+/.test(nextTrimmed) || /^[-*]\s+/.test(nextTrimmed));
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// If we're in a list and the next item is also a list item, continue the list
|
|
52
|
+
if ((inOrderedList || inUnorderedList) && nextListItemIndex !== -1) {
|
|
53
|
+
continue; // Skip this empty line but keep the list open
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Close any current lists before starting new paragraph
|
|
57
|
+
if (inOrderedList) {
|
|
58
|
+
processedLines.push('</ol>');
|
|
59
|
+
inOrderedList = false;
|
|
60
|
+
}
|
|
61
|
+
if (inUnorderedList) {
|
|
62
|
+
processedLines.push('</ul>');
|
|
63
|
+
inUnorderedList = false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Process accumulated paragraph
|
|
67
|
+
if (currentParagraph.length > 0) {
|
|
68
|
+
const paragraphContent = currentParagraph.join('<br>');
|
|
69
|
+
processedLines.push(`<p>${paragraphContent}</p>`);
|
|
70
|
+
currentParagraph = [];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Skip extra empty lines
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Check for numbered list items
|
|
78
|
+
if (/^\d+\.\s+/.test(trimmedLine)) {
|
|
79
|
+
// Finish any current paragraph
|
|
80
|
+
if (currentParagraph.length > 0) {
|
|
81
|
+
const paragraphContent = currentParagraph.join('<br>');
|
|
82
|
+
processedLines.push(`<p>${paragraphContent}</p>`);
|
|
83
|
+
currentParagraph = [];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!inOrderedList) {
|
|
87
|
+
if (inUnorderedList) {
|
|
88
|
+
processedLines.push('</ul>');
|
|
89
|
+
inUnorderedList = false;
|
|
90
|
+
}
|
|
91
|
+
processedLines.push('<ol>');
|
|
92
|
+
inOrderedList = true;
|
|
93
|
+
}
|
|
94
|
+
const content = trimmedLine.replace(/^\d+\.\s+/, '');
|
|
95
|
+
processedLines.push(`<li>${content}</li>`);
|
|
96
|
+
}
|
|
97
|
+
// Check for bullet list items
|
|
98
|
+
else if (/^[-*]\s+/.test(trimmedLine)) {
|
|
99
|
+
// Finish any current paragraph
|
|
100
|
+
if (currentParagraph.length > 0) {
|
|
101
|
+
const paragraphContent = currentParagraph.join('<br>');
|
|
102
|
+
processedLines.push(`<p>${paragraphContent}</p>`);
|
|
103
|
+
currentParagraph = [];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!inUnorderedList) {
|
|
107
|
+
if (inOrderedList) {
|
|
108
|
+
processedLines.push('</ol>');
|
|
109
|
+
inOrderedList = false;
|
|
110
|
+
}
|
|
111
|
+
processedLines.push('<ul>');
|
|
112
|
+
inUnorderedList = true;
|
|
113
|
+
}
|
|
114
|
+
const content = trimmedLine.replace(/^[-*]\s+/, '');
|
|
115
|
+
processedLines.push(`<li>${content}</li>`);
|
|
116
|
+
}
|
|
117
|
+
// Regular line
|
|
118
|
+
else {
|
|
119
|
+
// Close any lists
|
|
120
|
+
if (inOrderedList) {
|
|
121
|
+
processedLines.push('</ol>');
|
|
122
|
+
inOrderedList = false;
|
|
123
|
+
}
|
|
124
|
+
if (inUnorderedList) {
|
|
125
|
+
processedLines.push('</ul>');
|
|
126
|
+
inUnorderedList = false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Add to current paragraph
|
|
130
|
+
currentParagraph.push(trimmedLine);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Close any remaining lists
|
|
135
|
+
if (inOrderedList) processedLines.push('</ol>');
|
|
136
|
+
if (inUnorderedList) processedLines.push('</ul>');
|
|
137
|
+
|
|
138
|
+
// Process any remaining paragraph
|
|
139
|
+
if (currentParagraph.length > 0) {
|
|
140
|
+
const paragraphContent = currentParagraph.join('<br>');
|
|
141
|
+
processedLines.push(`<p>${paragraphContent}</p>`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return processedLines.join('\n\n');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
console.log('=== INPUT ===');
|
|
148
|
+
console.log(testInput);
|
|
149
|
+
console.log('\n=== OUTPUT ===');
|
|
150
|
+
console.log(markdownToHtml(testInput));
|