@s0nderlabs/anima-plugin-telegram 0.21.21 → 0.22.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/package.json +2 -2
- package/src/format.test.ts +47 -1
- package/src/format.ts +18 -0
- package/src/index.ts +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@s0nderlabs/anima-plugin-telegram",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Telegram gateway plugin for anima — long-poll bot, debounced dispatch, reactions, allowlist",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"test": "bun test"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@s0nderlabs/anima-core": "0.
|
|
42
|
+
"@s0nderlabs/anima-core": "0.22.0",
|
|
43
43
|
"grammy": "^1.42.0",
|
|
44
44
|
"zod": "^3.23.8"
|
|
45
45
|
}
|
package/src/format.test.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from 'bun:test'
|
|
2
|
-
import { formatInboundPreview, formatTelegramChannel } from './format'
|
|
2
|
+
import { formatInboundPreview, formatTelegramChannel, stripTelegramChannelEnvelope } from './format'
|
|
3
|
+
import { parseBypassCommand } from './session-state'
|
|
3
4
|
|
|
4
5
|
describe('formatTelegramChannel', () => {
|
|
5
6
|
it('wraps text in channel tags with username', () => {
|
|
@@ -44,6 +45,51 @@ describe('formatTelegramChannel', () => {
|
|
|
44
45
|
})
|
|
45
46
|
})
|
|
46
47
|
|
|
48
|
+
describe('stripTelegramChannelEnvelope', () => {
|
|
49
|
+
it('strips the envelope and returns inner text', () => {
|
|
50
|
+
expect(
|
|
51
|
+
stripTelegramChannelEnvelope(
|
|
52
|
+
'<channel source="telegram" chat="42" user="el">hello world</channel>',
|
|
53
|
+
),
|
|
54
|
+
).toBe('hello world')
|
|
55
|
+
})
|
|
56
|
+
it('returns input unchanged when no envelope present', () => {
|
|
57
|
+
expect(stripTelegramChannelEnvelope('hello world')).toBe('hello world')
|
|
58
|
+
expect(stripTelegramChannelEnvelope('/yolo')).toBe('/yolo')
|
|
59
|
+
})
|
|
60
|
+
it('preserves multi-line + nested-bracket content', () => {
|
|
61
|
+
expect(
|
|
62
|
+
stripTelegramChannelEnvelope(
|
|
63
|
+
'<channel source="telegram" chat="1" user="a">line 1\nline 2 with <br> tag</channel>',
|
|
64
|
+
),
|
|
65
|
+
).toBe('line 1\nline 2 with <br> tag')
|
|
66
|
+
})
|
|
67
|
+
// v0.22.0 regression: TG bypass commands (/yolo /perms /reset) fell through
|
|
68
|
+
// to the brain because parseBypassCommand was given the wrapped string. The
|
|
69
|
+
// wrapped string starts with '<channel' not '/', so the bypass parser
|
|
70
|
+
// returns null. After the strip, parseBypassCommand intercepts correctly.
|
|
71
|
+
it('lets parseBypassCommand intercept after strip (regression)', () => {
|
|
72
|
+
const wrapped = '<channel source="telegram" chat="1" user="el">/yolo</channel>'
|
|
73
|
+
expect(parseBypassCommand(wrapped)).toBeNull()
|
|
74
|
+
expect(parseBypassCommand(stripTelegramChannelEnvelope(wrapped))).toEqual({
|
|
75
|
+
command: '/yolo',
|
|
76
|
+
args: [],
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
it('handles /perms strict and /reset the same way', () => {
|
|
80
|
+
const yolo = '<channel source="telegram" chat="1" user="el">/perms strict</channel>'
|
|
81
|
+
expect(parseBypassCommand(stripTelegramChannelEnvelope(yolo))).toEqual({
|
|
82
|
+
command: '/perms',
|
|
83
|
+
args: ['strict'],
|
|
84
|
+
})
|
|
85
|
+
const reset = '<channel source="telegram" chat="1" user="el">/reset</channel>'
|
|
86
|
+
expect(parseBypassCommand(stripTelegramChannelEnvelope(reset))).toEqual({
|
|
87
|
+
command: '/reset',
|
|
88
|
+
args: [],
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
|
|
47
93
|
describe('formatInboundPreview', () => {
|
|
48
94
|
it('renders short message verbatim', () => {
|
|
49
95
|
expect(
|
package/src/format.ts
CHANGED
|
@@ -20,6 +20,24 @@ export function formatTelegramChannel(input: FormatTelegramChannelInput): string
|
|
|
20
20
|
return `<channel source="telegram" chat="${input.chatId}" user="${safeUser}">${safeText}</channel>`
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Inverse of `formatTelegramChannel`: strip the channel envelope and return
|
|
25
|
+
* the raw inner text. Used by the gateway's TG slot to feed bypass-command
|
|
26
|
+
* parsing the un-wrapped string (the wrapper would make `parseBypassCommand`'s
|
|
27
|
+
* `startsWith('/')` check fail and silently drop `/yolo` etc).
|
|
28
|
+
*
|
|
29
|
+
* v0.22.0: extracted into plugin-telegram so the regex source lives next to
|
|
30
|
+
* its forward counterpart `formatTelegramChannel`. If we ever change the
|
|
31
|
+
* envelope shape (add fields, swap quoting), both stay in sync.
|
|
32
|
+
*
|
|
33
|
+
* Returns the input unchanged when there is no envelope (idempotent — safe to
|
|
34
|
+
* call on already-stripped or non-TG input).
|
|
35
|
+
*/
|
|
36
|
+
const CHANNEL_ENVELOPE_RE = /^<channel[^>]*>([\s\S]*)<\/channel>$/
|
|
37
|
+
export function stripTelegramChannelEnvelope(text: string): string {
|
|
38
|
+
return text.replace(CHANNEL_ENVELOPE_RE, '$1')
|
|
39
|
+
}
|
|
40
|
+
|
|
23
41
|
/**
|
|
24
42
|
* One-line preview of an inbound TG message for TUI rows + activity log.
|
|
25
43
|
* Truncated to 80 chars; never includes the bot token or any envelope bytes.
|
package/src/index.ts
CHANGED
|
@@ -34,7 +34,11 @@ export {
|
|
|
34
34
|
formatApprovalResolution,
|
|
35
35
|
} from './listener'
|
|
36
36
|
export { buildSessionKey, sanitizeAgentName } from './session-key'
|
|
37
|
-
export {
|
|
37
|
+
export {
|
|
38
|
+
formatTelegramChannel,
|
|
39
|
+
formatInboundPreview,
|
|
40
|
+
stripTelegramChannelEnvelope,
|
|
41
|
+
} from './format'
|
|
38
42
|
export { RateLimiter } from './limits'
|
|
39
43
|
export { sanitizeInbound, type SanitizeReason, type SanitizeResult } from './sanitize'
|
|
40
44
|
export { formatPairingMessage } from './pairing-flow'
|