agent-messenger 2.6.2 → 2.7.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/.claude-plugin/plugin.json +1 -1
- package/dist/package.json +1 -1
- package/dist/src/platforms/webex/client.d.ts +3 -0
- package/dist/src/platforms/webex/client.d.ts.map +1 -1
- package/dist/src/platforms/webex/client.js +22 -8
- package/dist/src/platforms/webex/client.js.map +1 -1
- package/dist/src/platforms/webex/commands/snapshot.d.ts +0 -3
- package/dist/src/platforms/webex/commands/snapshot.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/snapshot.js +9 -47
- package/dist/src/platforms/webex/commands/snapshot.js.map +1 -1
- package/dist/src/platforms/webex/markdown-to-html.d.ts +3 -0
- package/dist/src/platforms/webex/markdown-to-html.d.ts.map +1 -0
- package/dist/src/platforms/webex/markdown-to-html.js +161 -0
- package/dist/src/platforms/webex/markdown-to-html.js.map +1 -0
- package/docs/content/docs/cli/webex.mdx +3 -11
- package/package.json +1 -1
- package/skills/agent-channeltalk/SKILL.md +1 -1
- package/skills/agent-channeltalkbot/SKILL.md +1 -1
- package/skills/agent-discord/SKILL.md +1 -1
- package/skills/agent-discordbot/SKILL.md +1 -1
- package/skills/agent-instagram/SKILL.md +1 -1
- package/skills/agent-kakaotalk/SKILL.md +1 -1
- package/skills/agent-line/SKILL.md +1 -1
- package/skills/agent-slack/SKILL.md +1 -1
- package/skills/agent-slackbot/SKILL.md +1 -1
- package/skills/agent-teams/SKILL.md +1 -1
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +6 -14
- package/skills/agent-webex/references/common-patterns.md +3 -32
- package/skills/agent-wechatbot/SKILL.md +1 -1
- package/skills/agent-whatsapp/SKILL.md +1 -1
- package/skills/agent-whatsappbot/SKILL.md +1 -1
- package/src/platforms/webex/client.test.ts +35 -0
- package/src/platforms/webex/client.ts +26 -9
- package/src/platforms/webex/commands/snapshot.test.ts +13 -41
- package/src/platforms/webex/commands/snapshot.ts +10 -61
- package/src/platforms/webex/markdown-to-html.test.ts +153 -0
- package/src/platforms/webex/markdown-to-html.ts +194 -0
- package/src/platforms/wechatbot/cli.ts +0 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
const BLOCK_PLACEHOLDER_PREFIX = '\u0000BLOCK'
|
|
2
|
+
const INLINE_PLACEHOLDER_PREFIX = '\u0000INLINE'
|
|
3
|
+
|
|
4
|
+
export function markdownToHtml(markdown: string): string {
|
|
5
|
+
if (markdown.length === 0) {
|
|
6
|
+
return ''
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const normalized = markdown.replace(/\r\n?/g, '\n')
|
|
10
|
+
if (normalized.trim().length === 0) {
|
|
11
|
+
return normalized
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const { text, blocks } = extractCodeBlocks(normalized)
|
|
15
|
+
const lines = text.split('\n')
|
|
16
|
+
const output: string[] = []
|
|
17
|
+
let paragraph: string[] = []
|
|
18
|
+
|
|
19
|
+
const flushParagraph = () => {
|
|
20
|
+
if (paragraph.length === 0) {
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
output.push(processInline(paragraph.join('\n')).replace(/\n/g, '<br/>'))
|
|
25
|
+
paragraph = []
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
for (let index = 0; index < lines.length; ) {
|
|
29
|
+
const line = lines[index]
|
|
30
|
+
const trimmed = line.trim()
|
|
31
|
+
|
|
32
|
+
if (trimmed.length === 0) {
|
|
33
|
+
flushParagraph()
|
|
34
|
+
index++
|
|
35
|
+
continue
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (isBlockPlaceholder(trimmed)) {
|
|
39
|
+
flushParagraph()
|
|
40
|
+
output.push(trimmed)
|
|
41
|
+
index++
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.*)$/)
|
|
46
|
+
if (headingMatch) {
|
|
47
|
+
flushParagraph()
|
|
48
|
+
output.push(`<h${headingMatch[1].length}>${processInline(headingMatch[2])}</h${headingMatch[1].length}>`)
|
|
49
|
+
index++
|
|
50
|
+
continue
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (/^---$/.test(trimmed)) {
|
|
54
|
+
flushParagraph()
|
|
55
|
+
output.push('<hr>')
|
|
56
|
+
index++
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (/^>\s?/.test(line)) {
|
|
61
|
+
flushParagraph()
|
|
62
|
+
const quoteLines: string[] = []
|
|
63
|
+
while (index < lines.length && /^>\s?/.test(lines[index])) {
|
|
64
|
+
quoteLines.push(lines[index].replace(/^>\s?/, ''))
|
|
65
|
+
index++
|
|
66
|
+
}
|
|
67
|
+
output.push(`<blockquote>${processInline(quoteLines.join('\n')).replace(/\n/g, '<br/>')}</blockquote>`)
|
|
68
|
+
continue
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (/^-\s+/.test(line)) {
|
|
72
|
+
flushParagraph()
|
|
73
|
+
const items: string[] = []
|
|
74
|
+
while (index < lines.length && /^-\s+/.test(lines[index])) {
|
|
75
|
+
items.push(`<li>${processInline(lines[index].replace(/^-\s+/, ''))}</li>`)
|
|
76
|
+
index++
|
|
77
|
+
}
|
|
78
|
+
output.push(`<ul>${items.join('')}</ul>`)
|
|
79
|
+
continue
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (/^\d+\.\s+/.test(line)) {
|
|
83
|
+
flushParagraph()
|
|
84
|
+
const items: string[] = []
|
|
85
|
+
while (index < lines.length && /^\d+\.\s+/.test(lines[index])) {
|
|
86
|
+
items.push(`<li>${processInline(lines[index].replace(/^\d+\.\s+/, ''))}</li>`)
|
|
87
|
+
index++
|
|
88
|
+
}
|
|
89
|
+
output.push(`<ol>${items.join('')}</ol>`)
|
|
90
|
+
continue
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
paragraph.push(line)
|
|
94
|
+
index++
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
flushParagraph()
|
|
98
|
+
|
|
99
|
+
return restorePlaceholders(output.join('<br/><br/>'), blocks)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function stripMarkdown(markdown: string): string {
|
|
103
|
+
return markdown
|
|
104
|
+
.replace(/\r\n?/g, '\n')
|
|
105
|
+
.replace(/```([a-zA-Z0-9_-]+)?\n?([\s\S]*?)```/g, (_, _language: string | undefined, code: string) => {
|
|
106
|
+
return code.replace(/\n$/, '')
|
|
107
|
+
})
|
|
108
|
+
.replace(/^---$/gm, '')
|
|
109
|
+
.replace(/^(#{1,6})\s+/gm, '')
|
|
110
|
+
.replace(/^>\s?/gm, '')
|
|
111
|
+
.replace(/^-\s+/gm, '')
|
|
112
|
+
.replace(/^\d+\.\s+/gm, '')
|
|
113
|
+
.replace(/\[([^\]]+)\]\(([^)\n]+)\)/g, '$1')
|
|
114
|
+
.replace(/`([^`\n]+)`/g, '$1')
|
|
115
|
+
.replace(/\*\*\*([^*\n]+)\*\*\*/g, '$1')
|
|
116
|
+
.replace(/\*\*([^*\n]+)\*\*/g, '$1')
|
|
117
|
+
.replace(/(^|[^\w])_([^_\n]+)_(?=[^\w]|$)/g, '$1$2')
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function processInline(markdown: string): string {
|
|
121
|
+
const placeholders: string[] = []
|
|
122
|
+
let text = markdown
|
|
123
|
+
|
|
124
|
+
text = text.replace(/`([^`\n]+)`/g, (_, code: string) => {
|
|
125
|
+
return createInlinePlaceholder(placeholders, `<code>${escapeHtml(code)}</code>`)
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
text = text.replace(/\[([^\]]+)\]\(([^)\n]+)\)/g, (_, label: string, url: string) => {
|
|
129
|
+
if (!isSafeUrl(url)) {
|
|
130
|
+
return processInline(label)
|
|
131
|
+
}
|
|
132
|
+
return createInlinePlaceholder(
|
|
133
|
+
placeholders,
|
|
134
|
+
`<a href="${escapeHtml(url)}">${processInline(label)}</a>`,
|
|
135
|
+
)
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
text = escapeHtml(text)
|
|
139
|
+
text = text.replace(/\*\*\*([^*\n]+)\*\*\*/g, '<strong><em>$1</em></strong>')
|
|
140
|
+
text = text.replace(/\*\*([^*\n]+)\*\*/g, '<strong>$1</strong>')
|
|
141
|
+
text = text.replace(/(^|[^\w])_([^_\n]+)_(?=[^\w]|$)/g, '$1<em>$2</em>')
|
|
142
|
+
|
|
143
|
+
return restorePlaceholders(text, placeholders)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function extractCodeBlocks(markdown: string): { text: string; blocks: string[] } {
|
|
147
|
+
const blocks: string[] = []
|
|
148
|
+
const text = markdown.replace(/```([a-zA-Z0-9_-]+)?\n([\s\S]*?)\n```/g, (_, language: string | undefined, code: string) => {
|
|
149
|
+
const className = language ? ` class="language-${escapeHtml(language)}"` : ''
|
|
150
|
+
return createBlockPlaceholder(blocks, `<pre><code${className}>${escapeHtml(code)}</code></pre>`)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
return { text, blocks }
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function createBlockPlaceholder(blocks: string[], html: string): string {
|
|
157
|
+
const token = `${BLOCK_PLACEHOLDER_PREFIX}${blocks.length}\u0000`
|
|
158
|
+
blocks.push(html)
|
|
159
|
+
return token
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function createInlinePlaceholder(placeholders: string[], html: string): string {
|
|
163
|
+
const token = `${INLINE_PLACEHOLDER_PREFIX}${placeholders.length}\u0000`
|
|
164
|
+
placeholders.push(html)
|
|
165
|
+
return token
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function isBlockPlaceholder(value: string): boolean {
|
|
169
|
+
return new RegExp(`^${BLOCK_PLACEHOLDER_PREFIX}\\d+\\u0000$`).test(value)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function restorePlaceholders(text: string, values: string[]): string {
|
|
173
|
+
let restored = text
|
|
174
|
+
for (const [index, value] of values.entries()) {
|
|
175
|
+
restored = restored.replaceAll(`${BLOCK_PLACEHOLDER_PREFIX}${index}\u0000`, value)
|
|
176
|
+
restored = restored.replaceAll(`${INLINE_PLACEHOLDER_PREFIX}${index}\u0000`, value)
|
|
177
|
+
}
|
|
178
|
+
return restored
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const SAFE_URL_PATTERN = /^(https?:|mailto:|\/|#)/i
|
|
182
|
+
|
|
183
|
+
function isSafeUrl(url: string): boolean {
|
|
184
|
+
return SAFE_URL_PATTERN.test(url.trim())
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function escapeHtml(value: string): string {
|
|
188
|
+
return value
|
|
189
|
+
.replaceAll('&', '&')
|
|
190
|
+
.replaceAll('<', '<')
|
|
191
|
+
.replaceAll('>', '>')
|
|
192
|
+
.replaceAll('"', '"')
|
|
193
|
+
.replaceAll("'", ''')
|
|
194
|
+
}
|
|
File without changes
|