agent-messenger 2.35.0 → 2.36.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.
Files changed (71) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/package.json +1 -1
  3. package/dist/src/platforms/teams/client.d.ts +4 -4
  4. package/dist/src/platforms/teams/client.d.ts.map +1 -1
  5. package/dist/src/platforms/teams/client.js +14 -14
  6. package/dist/src/platforms/teams/client.js.map +1 -1
  7. package/dist/src/platforms/teams/commands/chat.d.ts +2 -0
  8. package/dist/src/platforms/teams/commands/chat.d.ts.map +1 -1
  9. package/dist/src/platforms/teams/commands/chat.js +7 -2
  10. package/dist/src/platforms/teams/commands/chat.js.map +1 -1
  11. package/dist/src/platforms/teams/commands/format.d.ts +3 -0
  12. package/dist/src/platforms/teams/commands/format.d.ts.map +1 -0
  13. package/dist/src/platforms/teams/commands/format.js +10 -0
  14. package/dist/src/platforms/teams/commands/format.js.map +1 -0
  15. package/dist/src/platforms/teams/commands/message.d.ts +1 -0
  16. package/dist/src/platforms/teams/commands/message.d.ts.map +1 -1
  17. package/dist/src/platforms/teams/commands/message.js +4 -1
  18. package/dist/src/platforms/teams/commands/message.js.map +1 -1
  19. package/dist/src/platforms/teams/html-sanitizer.d.ts +17 -0
  20. package/dist/src/platforms/teams/html-sanitizer.d.ts.map +1 -0
  21. package/dist/src/platforms/teams/html-sanitizer.js +120 -0
  22. package/dist/src/platforms/teams/html-sanitizer.js.map +1 -0
  23. package/dist/src/platforms/teams/index.d.ts +1 -1
  24. package/dist/src/platforms/teams/index.d.ts.map +1 -1
  25. package/dist/src/platforms/teams/index.js.map +1 -1
  26. package/dist/src/platforms/teams/types.d.ts +1 -0
  27. package/dist/src/platforms/teams/types.d.ts.map +1 -1
  28. package/dist/src/platforms/teams/types.js.map +1 -1
  29. package/dist/src/platforms/webex/client.d.ts.map +1 -1
  30. package/dist/src/platforms/webex/client.js +1 -1
  31. package/dist/src/platforms/webex/client.js.map +1 -1
  32. package/dist/src/shared/utils/markdown-to-html.d.ts.map +1 -0
  33. package/dist/src/{platforms/webex → shared/utils}/markdown-to-html.js +0 -0
  34. package/dist/src/shared/utils/markdown-to-html.js.map +1 -0
  35. package/package.json +1 -1
  36. package/skills/agent-channeltalk/SKILL.md +1 -1
  37. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  38. package/skills/agent-discord/SKILL.md +1 -1
  39. package/skills/agent-discordbot/SKILL.md +1 -1
  40. package/skills/agent-imessage/SKILL.md +1 -1
  41. package/skills/agent-instagram/SKILL.md +1 -1
  42. package/skills/agent-kakaotalk/SKILL.md +1 -1
  43. package/skills/agent-line/SKILL.md +1 -1
  44. package/skills/agent-slack/SKILL.md +1 -1
  45. package/skills/agent-slackbot/SKILL.md +1 -1
  46. package/skills/agent-teams/SKILL.md +44 -2
  47. package/skills/agent-teams/references/common-patterns.md +2 -2
  48. package/skills/agent-telegram/SKILL.md +1 -1
  49. package/skills/agent-telegrambot/SKILL.md +1 -1
  50. package/skills/agent-webex/SKILL.md +1 -1
  51. package/skills/agent-webexbot/SKILL.md +1 -1
  52. package/skills/agent-wechatbot/SKILL.md +1 -1
  53. package/skills/agent-whatsapp/SKILL.md +1 -1
  54. package/skills/agent-whatsappbot/SKILL.md +1 -1
  55. package/src/platforms/teams/client.test.ts +127 -0
  56. package/src/platforms/teams/client.ts +27 -14
  57. package/src/platforms/teams/commands/chat.test.ts +70 -1
  58. package/src/platforms/teams/commands/chat.ts +15 -4
  59. package/src/platforms/teams/commands/format.ts +12 -0
  60. package/src/platforms/teams/commands/message.test.ts +56 -0
  61. package/src/platforms/teams/commands/message.ts +6 -2
  62. package/src/platforms/teams/html-sanitizer.test.ts +123 -0
  63. package/src/platforms/teams/html-sanitizer.ts +134 -0
  64. package/src/platforms/teams/index.ts +1 -0
  65. package/src/platforms/teams/types.ts +2 -0
  66. package/src/platforms/webex/client.ts +2 -1
  67. package/src/{platforms/webex → shared/utils}/markdown-to-html.test.ts +7 -0
  68. package/src/{platforms/webex → shared/utils}/markdown-to-html.ts +0 -0
  69. package/dist/src/platforms/webex/markdown-to-html.d.ts.map +0 -1
  70. package/dist/src/platforms/webex/markdown-to-html.js.map +0 -1
  71. /package/dist/src/{platforms/webex → shared/utils}/markdown-to-html.d.ts +0 -0
@@ -7,13 +7,16 @@ import { TeamsClient } from '../client'
7
7
  import { TeamsCredentialManager } from '../credential-manager'
8
8
  import type { TeamsMessage } from '../types'
9
9
  import { TeamsAuthCapabilityError } from '../types'
10
+ import { resolveFormat } from './format'
10
11
 
11
12
  export async function sendAction(
12
13
  teamId: string,
13
14
  channelId: string,
14
15
  content: string,
15
- options: { pretty?: boolean; thread?: string },
16
+ options: { pretty?: boolean; thread?: string; format?: string },
16
17
  ): Promise<void> {
18
+ const format = resolveFormat(options.format, options.pretty)
19
+
17
20
  try {
18
21
  const credManager = new TeamsCredentialManager()
19
22
  const cred = await credManager.getTokenWithExpiry()
@@ -29,7 +32,7 @@ export async function sendAction(
29
32
  accountType: cred.accountType,
30
33
  region: cred.region,
31
34
  })
32
- const message = await client.sendMessage(teamId, channelId, content, options.thread)
35
+ const message = await client.sendMessage(teamId, channelId, content, options.thread, format)
33
36
 
34
37
  const output = {
35
38
  id: message.id,
@@ -274,6 +277,7 @@ export const messageCommand = new Command('message')
274
277
  .argument('<channel-id>', 'Channel ID')
275
278
  .argument('<content>', 'Message content')
276
279
  .option('--thread <message-id>', 'Reply to a thread root message')
280
+ .option('--format <format>', 'Message format: text, markdown, or html', 'text')
277
281
  .option('--pretty', 'Pretty print JSON output')
278
282
  .action(sendAction),
279
283
  )
@@ -0,0 +1,123 @@
1
+ import { describe, expect, it } from 'bun:test'
2
+
3
+ import { sanitizeTeamsHtml } from './html-sanitizer'
4
+
5
+ describe('sanitizeTeamsHtml', () => {
6
+ it('keeps a Teams mention tag with its id attribute', () => {
7
+ expect(sanitizeTeamsHtml('Hey <at id="29:x">John</at>')).toBe('Hey <at id="29:x">John</at>')
8
+ })
9
+
10
+ it('keeps whitelisted formatting tags', () => {
11
+ expect(sanitizeTeamsHtml('<b>bold</b>')).toBe('<b>bold</b>')
12
+ })
13
+
14
+ it('escapes a disallowed tag with a dangerous attribute', () => {
15
+ expect(sanitizeTeamsHtml('<img src=x onerror=alert(1)>')).toBe('&lt;img src=x onerror=alert(1)&gt;')
16
+ })
17
+
18
+ it('escapes script tags entirely', () => {
19
+ expect(sanitizeTeamsHtml('<script>alert(1)</script>')).toBe('&lt;script&gt;alert(1)&lt;/script&gt;')
20
+ })
21
+
22
+ it('keeps a whitelisted tag but drops its disallowed attribute', () => {
23
+ expect(sanitizeTeamsHtml('<b onclick="evil()">x</b>')).toBe('<b>x</b>')
24
+ })
25
+
26
+ it('drops an unsafe href but keeps the anchor tag', () => {
27
+ expect(sanitizeTeamsHtml('<a href="javascript:alert(1)">x</a>')).toBe('<a>x</a>')
28
+ })
29
+
30
+ it('escapes a bare < that is not part of a recognized tag', () => {
31
+ expect(sanitizeTeamsHtml('a < b')).toBe('a &lt; b')
32
+ })
33
+
34
+ describe('bypass attempts', () => {
35
+ it('blocks case-variant script tags', () => {
36
+ expect(sanitizeTeamsHtml('<ScRiPt>x</ScRiPt>')).toBe('&lt;ScRiPt&gt;x&lt;/ScRiPt&gt;')
37
+ })
38
+
39
+ it('recognizes a whitelisted tag regardless of case', () => {
40
+ expect(sanitizeTeamsHtml('<AT ID="x">John</AT>')).toBe('<at id="x">John</at>')
41
+ })
42
+
43
+ it('blocks a tag name followed directly by non-whitespace garbage', () => {
44
+ const result = sanitizeTeamsHtml('<script/x>alert(1)</script>')
45
+ expect(result).not.toContain('<script')
46
+ expect(result).toContain('&lt;script/x&gt;')
47
+ })
48
+
49
+ it('blocks a tag name followed by whitespace before the closing bracket', () => {
50
+ const result = sanitizeTeamsHtml('<script\n>alert(1)</script>')
51
+ expect(result).not.toContain('<script')
52
+ expect(result).toContain('&lt;script')
53
+ })
54
+
55
+ it('drops a quoted dangerous attribute alongside an allowed one', () => {
56
+ expect(sanitizeTeamsHtml('<at id="x" onload="y">John</at>')).toBe('<at id="x">John</at>')
57
+ })
58
+
59
+ it('drops an unquoted dangerous attribute alongside an allowed one', () => {
60
+ expect(sanitizeTeamsHtml('<at id=x onerror=y>John</at>')).toBe('<at id="x">John</at>')
61
+ })
62
+
63
+ it('never produces a live tag from nested/malformed markup', () => {
64
+ const result = sanitizeTeamsHtml('<<script>script>')
65
+ expect(result).not.toMatch(/<script[^>]*>/)
66
+ expect(result).toBe('&lt;&lt;script&gt;script&gt;')
67
+ })
68
+
69
+ it('sanitizes a disallowed tag nested inside a whitelisted one', () => {
70
+ expect(sanitizeTeamsHtml('<b><script>alert(1)</script></b>')).toBe('<b>&lt;script&gt;alert(1)&lt;/script&gt;</b>')
71
+ })
72
+
73
+ it('does not double-escape already-escaped content', () => {
74
+ expect(sanitizeTeamsHtml('&lt;script&gt;')).toBe('&lt;script&gt;')
75
+ })
76
+
77
+ it('accepts void/self-closing br in any spelling', () => {
78
+ expect(sanitizeTeamsHtml('<br>')).toBe('<br>')
79
+ expect(sanitizeTeamsHtml('<br/>')).toBe('<br>')
80
+ expect(sanitizeTeamsHtml('<br />')).toBe('<br>')
81
+ })
82
+
83
+ it('allows an https href', () => {
84
+ expect(sanitizeTeamsHtml('<a href="https://ok.com">link</a>')).toBe('<a href="https://ok.com">link</a>')
85
+ })
86
+
87
+ it('drops a javascript: href', () => {
88
+ expect(sanitizeTeamsHtml('<a href="javascript:alert(1)">link</a>')).toBe('<a>link</a>')
89
+ })
90
+
91
+ it('drops a javascript: href even with leading whitespace before it', () => {
92
+ expect(sanitizeTeamsHtml('<a href=" javascript:alert(1)">link</a>')).toBe('<a>link</a>')
93
+ })
94
+
95
+ it('escapes hyphenated custom elements instead of rewriting them to a shorter allowed tag', () => {
96
+ // Without a hyphen in the tag-name pattern, "<a-b>" matched as "<a>" plus
97
+ // leftover text, silently rewriting an unknown element into an anchor.
98
+ expect(sanitizeTeamsHtml('<a-b onclick="x">hi</a-b>')).toBe('&lt;a-b onclick="x"&gt;hi&lt;/a-b&gt;')
99
+ expect(sanitizeTeamsHtml('<my-widget>x</my-widget>')).toBe('&lt;my-widget&gt;x&lt;/my-widget&gt;')
100
+ })
101
+
102
+ it('escapes tag names that merely start with an allowed name', () => {
103
+ // A tag name must end at a real boundary. Otherwise "<at:id>" matched the
104
+ // "at" prefix and was promoted into a Teams mention, and "<b_extra>" into
105
+ // bold — arbitrary markup turning into formatting or a mention.
106
+ expect(sanitizeTeamsHtml('<at:id>x</at:id>')).toBe('&lt;at:id&gt;x&lt;/at:id&gt;')
107
+ expect(sanitizeTeamsHtml('<b_extra>x</b_extra>')).toBe('&lt;b_extra&gt;x&lt;/b_extra&gt;')
108
+ expect(sanitizeTeamsHtml('<b.bold>x</b.bold>')).toBe('&lt;b.bold&gt;x&lt;/b.bold&gt;')
109
+ expect(sanitizeTeamsHtml('<a:link href="https://evil.com">x</a:link>')).toBe(
110
+ '&lt;a:link href="https://evil.com"&gt;x&lt;/a:link&gt;',
111
+ )
112
+ })
113
+
114
+ it('ignores attribute names that merely end with an allowed name', () => {
115
+ // An attribute name must start at a real boundary. Otherwise "foo.id"
116
+ // was truncated to "id" and "foo.href" to "href", letting arbitrary
117
+ // attributes forge a mention or a link.
118
+ expect(sanitizeTeamsHtml('<at foo.id="29:evil">J</at>')).toBe('<at>J</at>')
119
+ expect(sanitizeTeamsHtml('<at x:id="29:evil">J</at>')).toBe('<at>J</at>')
120
+ expect(sanitizeTeamsHtml('<a foo.href="https://evil.com">x</a>')).toBe('<a>x</a>')
121
+ })
122
+ })
123
+ })
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Whitelist-based sanitizer for `--format html` content.
3
+ *
4
+ * Kept local to the Teams platform (not `src/shared/utils/`) because `<at>`
5
+ * is a Teams-specific mention marker — sharing this out would leak
6
+ * Teams-only semantics into webex's transformer.
7
+ *
8
+ * This is a tag/attribute whitelist, not a full HTML parser: it recognizes
9
+ * `<name ...>` / `</name>` tokens with a regex, keeps the ones on the
10
+ * whitelist (stripping any attribute not explicitly allowed for that tag),
11
+ * and escapes everything else — including malformed or disallowed tags and
12
+ * any stray `<`/`>` that isn't part of a recognized tag. Text that has no
13
+ * literal `<`/`>` (e.g. already-escaped entities like `&lt;script&gt;`)
14
+ * passes through untouched, so content is never double-escaped.
15
+ */
16
+
17
+ const ALLOWED_TAGS = new Set([
18
+ 'at',
19
+ 'a',
20
+ 'b',
21
+ 'i',
22
+ 'u',
23
+ 's',
24
+ 'strong',
25
+ 'em',
26
+ 'code',
27
+ 'pre',
28
+ 'br',
29
+ 'p',
30
+ 'ul',
31
+ 'ol',
32
+ 'li',
33
+ 'blockquote',
34
+ 'h1',
35
+ 'h2',
36
+ 'h3',
37
+ 'h4',
38
+ 'h5',
39
+ 'h6',
40
+ 'hr',
41
+ ])
42
+
43
+ // Same rule as src/shared/utils/markdown-to-html.ts's SAFE_URL_PATTERN, kept
44
+ // as a separate copy here since this module intentionally does not import
45
+ // from the shared markdown transformer (see the file-level comment above).
46
+ const SAFE_URL_PATTERN = /^(https?:|mailto:|\/|#)/i
47
+
48
+ // Captures: 1) leading "/" for a closing tag, 2) the tag name, 3) everything
49
+ // else up to the closing ">" (attributes and/or a trailing self-closing
50
+ // "/"). Requires a letter immediately after "<" (or after "</"), so a bare
51
+ // "<" not followed by a tag name — e.g. the outer "<" in "<<script>" — is
52
+ // left as plain text instead of being absorbed into a match.
53
+ //
54
+ // The name must end at a real boundary — whitespace, "/" or ">" — so a name is
55
+ // only ever matched in full. Without that lookahead a tag whose name merely
56
+ // starts with an allowed one was promoted into it: "<at:id>" became a Teams
57
+ // mention and "<b_extra>" became bold. Requiring the boundary makes those fail
58
+ // the whitelist and get escaped like any other unknown tag.
59
+ const TAG_PATTERN = /<(\/)?([a-zA-Z][a-zA-Z0-9-]*)(?=[\s/>])([^<>]*)>/g
60
+
61
+ // The name must likewise start at a boundary — the beginning of the attribute
62
+ // section, whitespace, or the "/" of a self-closing tag. Scanning without one
63
+ // let a disallowed name be truncated to an allowed suffix, so `foo.id` was read
64
+ // as `id` and `foo.href` as `href`, forging mentions and links out of arbitrary
65
+ // attributes.
66
+ const ATTR_PATTERN = /(?<=^|[\s/])([a-zA-Z][a-zA-Z0-9-]*)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/g
67
+
68
+ export function sanitizeTeamsHtml(html: string): string {
69
+ let result = ''
70
+ let lastIndex = 0
71
+ TAG_PATTERN.lastIndex = 0
72
+
73
+ let match: RegExpExecArray | null
74
+ while ((match = TAG_PATTERN.exec(html)) !== null) {
75
+ result += escapeAngles(html.slice(lastIndex, match.index))
76
+ result += sanitizeTag(match)
77
+ lastIndex = TAG_PATTERN.lastIndex
78
+ }
79
+ result += escapeAngles(html.slice(lastIndex))
80
+
81
+ return result
82
+ }
83
+
84
+ function sanitizeTag(match: RegExpExecArray): string {
85
+ const [fullMatch, closingSlash, rawName, rest] = match
86
+ const name = rawName.toLowerCase()
87
+
88
+ if (!ALLOWED_TAGS.has(name)) {
89
+ return escapeAngles(fullMatch)
90
+ }
91
+
92
+ if (closingSlash) {
93
+ return `</${name}>`
94
+ }
95
+
96
+ const attrs = parseAttributes(rest)
97
+ const kept: string[] = []
98
+
99
+ if (name === 'at') {
100
+ const id = attrs.get('id')
101
+ if (id !== undefined) kept.push(`id="${escapeAttributeValue(id)}"`)
102
+ } else if (name === 'a') {
103
+ const href = attrs.get('href')
104
+ if (href !== undefined && isSafeUrl(href)) kept.push(`href="${escapeAttributeValue(href)}"`)
105
+ }
106
+
107
+ return kept.length > 0 ? `<${name} ${kept.join(' ')}>` : `<${name}>`
108
+ }
109
+
110
+ function parseAttributes(rest: string): Map<string, string> {
111
+ const attrs = new Map<string, string>()
112
+ ATTR_PATTERN.lastIndex = 0
113
+
114
+ let match: RegExpExecArray | null
115
+ while ((match = ATTR_PATTERN.exec(rest)) !== null) {
116
+ const name = match[1].toLowerCase()
117
+ const value = match[2] ?? match[3] ?? match[4] ?? ''
118
+ if (!attrs.has(name)) attrs.set(name, value)
119
+ }
120
+
121
+ return attrs
122
+ }
123
+
124
+ function isSafeUrl(url: string): boolean {
125
+ return SAFE_URL_PATTERN.test(url.trim())
126
+ }
127
+
128
+ function escapeAngles(text: string): string {
129
+ return text.replaceAll('<', '&lt;').replaceAll('>', '&gt;')
130
+ }
131
+
132
+ function escapeAttributeValue(value: string): string {
133
+ return value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;')
134
+ }
@@ -22,6 +22,7 @@ export type {
22
22
  TeamsListenerEventMap,
23
23
  TeamsMention,
24
24
  TeamsMessage,
25
+ TeamsMessageFormat,
25
26
  TeamsRealtimeMessage,
26
27
  TeamsReaction,
27
28
  TeamsSearchResult,
@@ -87,6 +87,8 @@ export type TeamsAccountType = 'work' | 'personal'
87
87
 
88
88
  export type TeamsRegion = 'amer' | 'emea' | 'apac'
89
89
 
90
+ export type TeamsMessageFormat = 'text' | 'markdown' | 'html'
91
+
90
92
  export type TeamsAuthMethod = 'device-code' | 'browser' | 'extracted' | 'manual'
91
93
 
92
94
  export interface TeamsAccount {
@@ -1,5 +1,7 @@
1
1
  import { createHash } from 'node:crypto'
2
2
 
3
+ import { escapeHtml, markdownToHtml, stripMarkdown } from '@/shared/utils/markdown-to-html'
4
+
3
5
  import { WebexCredentialManager } from './credential-manager'
4
6
  import { WebexEncryptionService } from './encryption'
5
7
  import type { WebexScr } from './encryption'
@@ -11,7 +13,6 @@ import {
11
13
  toRestId,
12
14
  } from './id-normalizer'
13
15
  import { KmsKeyProvider } from './kms-key-provider'
14
- import { escapeHtml, markdownToHtml, stripMarkdown } from './markdown-to-html'
15
16
  import type { WebexConfig, WebexMembership, WebexMessage, WebexPerson, WebexSpace } from './types'
16
17
  import { WebexError } from './types'
17
18
 
@@ -112,6 +112,13 @@ describe('markdownToHtml', () => {
112
112
  it('preserves whitespace-only input', () => {
113
113
  expect(markdownToHtml(' ')).toBe(' ')
114
114
  })
115
+
116
+ it('does not clobber a fenced block with an inline placeholder on the same line', () => {
117
+ const result = markdownToHtml('Run `npm i` then ```\ncode here\n``` done')
118
+
119
+ expect(result).toContain('<code>npm i</code>')
120
+ expect(result).toContain('code here')
121
+ })
115
122
  })
116
123
 
117
124
  describe('stripMarkdown', () => {
@@ -1 +0,0 @@
1
- {"version":3,"file":"markdown-to-html.d.ts","sourceRoot":"","sources":["../../../../src/platforms/webex/markdown-to-html.ts"],"names":[],"mappings":"AAGA,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgGvD;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgBtD;AAqED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOhD"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"markdown-to-html.js","sourceRoot":"","sources":["../../../../src/platforms/webex/markdown-to-html.ts"],"names":[],"mappings":"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"}