@pedrohnas/opencode-telegram 1.2.1 → 1.3.1
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/skills/playwright-cli/data/page-2026-02-09T02-40-45-070Z.png +0 -0
- package/.claude/skills/playwright-cli/data/page-2026-02-09T02-41-15-698Z.yml +168 -0
- package/.claude/skills/playwright-cli/data/page-2026-02-09T02-41-25-514Z.yml +219 -0
- package/.claude/skills/playwright-cli/data/page-2026-02-09T02-41-40-888Z.yml +221 -0
- package/.claude/skills/playwright-cli/data/page-2026-02-09T02-41-46-079Z.yml +230 -0
- package/.claude/skills/playwright-cli/data/page-2026-02-09T02-41-53-985Z.yml +235 -0
- package/.claude/skills/playwright-cli/data/page-2026-02-09T02-42-03-227Z.yml +235 -0
- package/.claude/skills/playwright-cli/data/page-2026-02-09T02-42-08-587Z.yml +248 -0
- package/.claude/skills/playwright-cli/data/page-2026-02-09T02-42-16-524Z.yml +234 -0
- package/.claude/skills/playwright-cli/data/page-2026-02-09T02-42-26-086Z.yml +196 -0
- package/docs/AUDIT.md +193 -0
- package/docs/PROGRESS.md +191 -0
- package/docs/plans/phase-5.md +410 -0
- package/docs/plans/phase-6.5.md +426 -0
- package/docs/plans/phase-6.md +349 -0
- package/e2e/helpers.ts +34 -0
- package/e2e/phase-5.test.ts +295 -0
- package/e2e/phase-6.5.test.ts +239 -0
- package/e2e/phase-6.test.ts +302 -0
- package/package.json +5 -2
- package/src/api-server.test.ts +309 -0
- package/src/api-server.ts +201 -0
- package/src/bot.test.ts +354 -0
- package/src/bot.ts +200 -2
- package/src/config.test.ts +16 -0
- package/src/config.ts +4 -0
- package/src/event-bus.test.ts +337 -1
- package/src/event-bus.ts +83 -3
- package/src/handlers/agents.test.ts +122 -0
- package/src/handlers/agents.ts +93 -0
- package/src/handlers/media.test.ts +264 -0
- package/src/handlers/media.ts +168 -0
- package/src/handlers/models.test.ts +319 -0
- package/src/handlers/models.ts +191 -0
- package/src/index.ts +15 -0
- package/src/send/draft-stream.test.ts +76 -0
- package/src/send/draft-stream.ts +13 -1
- package/src/session-manager.test.ts +46 -0
- package/src/session-manager.ts +10 -1
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
- generic [active] [ref=e1]:
|
|
2
|
+
- generic [ref=e3]:
|
|
3
|
+
- region "Site notifications" [ref=e4]:
|
|
4
|
+
- generic [ref=e8]:
|
|
5
|
+
- generic [ref=e9]: ⚠️
|
|
6
|
+
- alert [ref=e11]:
|
|
7
|
+
- text: "Security Update: Classic tokens have been revoked. Granular tokens are now limited to 90 days and require 2FA by default. Update your CI/CD workflows to avoid disruption."
|
|
8
|
+
- link "Learn more about npm authentication changes" [ref=e12] [cursor=pointer]:
|
|
9
|
+
- /url: https://gh.io/all-npm-classic-tokens-revoked
|
|
10
|
+
- text: Learn more
|
|
11
|
+
- text: .
|
|
12
|
+
- button "Close notification" [ref=e13] [cursor=pointer]: ×
|
|
13
|
+
- generic [ref=e14]:
|
|
14
|
+
- banner [ref=e15]:
|
|
15
|
+
- generic [ref=e16]:
|
|
16
|
+
- generic [ref=e17]:
|
|
17
|
+
- text: "skip to:"
|
|
18
|
+
- link "skip to content" [ref=e18] [cursor=pointer]:
|
|
19
|
+
- /url: "#main"
|
|
20
|
+
- text: content
|
|
21
|
+
- link "skip to package search" [ref=e19] [cursor=pointer]:
|
|
22
|
+
- /url: "#search"
|
|
23
|
+
- text: package search
|
|
24
|
+
- generic [ref=e20]:
|
|
25
|
+
- generic [ref=e21]: ❤
|
|
26
|
+
- navigation "Product Navigation" [ref=e22]:
|
|
27
|
+
- list [ref=e23]:
|
|
28
|
+
- listitem [ref=e24]:
|
|
29
|
+
- link "Pro" [ref=e25] [cursor=pointer]:
|
|
30
|
+
- /url: /products/pro
|
|
31
|
+
- listitem [ref=e26]:
|
|
32
|
+
- link "Teams" [ref=e27] [cursor=pointer]:
|
|
33
|
+
- /url: /products/teams
|
|
34
|
+
- listitem [ref=e28]:
|
|
35
|
+
- link "Pricing" [ref=e29] [cursor=pointer]:
|
|
36
|
+
- /url: /products
|
|
37
|
+
- listitem [ref=e30]:
|
|
38
|
+
- link "Documentation" [ref=e31] [cursor=pointer]:
|
|
39
|
+
- /url: https://docs.npmjs.com
|
|
40
|
+
- generic [ref=e33]:
|
|
41
|
+
- generic [ref=e34]: npm
|
|
42
|
+
- link "Npm" [ref=e36] [cursor=pointer]:
|
|
43
|
+
- /url: /
|
|
44
|
+
- img [ref=e37]
|
|
45
|
+
- generic [ref=e40]:
|
|
46
|
+
- generic [ref=e42]:
|
|
47
|
+
- img [ref=e44]
|
|
48
|
+
- combobox "Search packages" [ref=e50]
|
|
49
|
+
- button "Search" [ref=e52]
|
|
50
|
+
- navigation [ref=e54]:
|
|
51
|
+
- button "Profile menu" [ref=e55]:
|
|
52
|
+
- generic [ref=e56]: Menu
|
|
53
|
+
- img [ref=e57]
|
|
54
|
+
- img [ref=e59]
|
|
55
|
+
- main [ref=e62]:
|
|
56
|
+
- generic [ref=e63]:
|
|
57
|
+
- complementary [ref=e64]:
|
|
58
|
+
- heading "Sidebar" [level=2] [ref=e65]
|
|
59
|
+
- generic [ref=e66]:
|
|
60
|
+
- navigation "Settings navigation" [ref=e67]:
|
|
61
|
+
- list [ref=e68]:
|
|
62
|
+
- listitem [ref=e69]:
|
|
63
|
+
- link "Profile" [ref=e70] [cursor=pointer]:
|
|
64
|
+
- /url: /~pedrohnas
|
|
65
|
+
- img [ref=e71]
|
|
66
|
+
- text: Profile
|
|
67
|
+
- listitem [ref=e73]:
|
|
68
|
+
- link "Packages" [ref=e74] [cursor=pointer]:
|
|
69
|
+
- /url: /settings/pedrohnas/packages
|
|
70
|
+
- img [ref=e75]
|
|
71
|
+
- text: Packages
|
|
72
|
+
- listitem [ref=e77]:
|
|
73
|
+
- link "Account" [ref=e78] [cursor=pointer]:
|
|
74
|
+
- /url: /settings/pedrohnas/profile
|
|
75
|
+
- img [ref=e79]
|
|
76
|
+
- text: Account
|
|
77
|
+
- listitem [ref=e81]:
|
|
78
|
+
- link "Billing Info" [ref=e82] [cursor=pointer]:
|
|
79
|
+
- /url: /settings/pedrohnas/billing
|
|
80
|
+
- img [ref=e83]
|
|
81
|
+
- text: Billing Info
|
|
82
|
+
- listitem [ref=e85]:
|
|
83
|
+
- link "Access Tokens" [ref=e86] [cursor=pointer]:
|
|
84
|
+
- /url: /settings/pedrohnas/tokens
|
|
85
|
+
- img [ref=e87]
|
|
86
|
+
- text: Access Tokens
|
|
87
|
+
- generic [ref=e89]:
|
|
88
|
+
- heading "Organizations" [level=3] [ref=e90]
|
|
89
|
+
- link "Create New Organization" [ref=e91] [cursor=pointer]:
|
|
90
|
+
- /url: /org/create
|
|
91
|
+
- text: +
|
|
92
|
+
- generic [ref=e92]: Create New Organization
|
|
93
|
+
- paragraph [ref=e93]: None
|
|
94
|
+
- generic [ref=e169]:
|
|
95
|
+
- generic [ref=e170]:
|
|
96
|
+
- generic [ref=e171]:
|
|
97
|
+
- heading "New Granular Access Token" [level=1] [ref=e172]
|
|
98
|
+
- link "View token documentation" [ref=e173] [cursor=pointer]:
|
|
99
|
+
- /url: https://docs.npmjs.com/creating-and-viewing-access-tokens#creating-granular-access-tokens-on-the-website
|
|
100
|
+
- paragraph [ref=e176]:
|
|
101
|
+
- link "Granular access tokens" [ref=e177] [cursor=pointer]:
|
|
102
|
+
- /url: https://docs.npmjs.com/about-access-tokens#about-granular-access-tokens
|
|
103
|
+
- text: provide the most control by allowing you to configure fine-grained, tightly scoped permissions for your packages and organizations.
|
|
104
|
+
- generic [ref=e178]:
|
|
105
|
+
- generic [ref=e179]:
|
|
106
|
+
- heading "General" [level=2] [ref=e180]
|
|
107
|
+
- generic [ref=e182]:
|
|
108
|
+
- generic [ref=e183]: Token name *
|
|
109
|
+
- caption [ref=e184]: Provide a unique name.
|
|
110
|
+
- textbox "Token name" [ref=e186]: opencode-telegram-publish
|
|
111
|
+
- generic [ref=e187]:
|
|
112
|
+
- generic [ref=e189]: Description (optional)
|
|
113
|
+
- caption [ref=e190]: What is this token for?
|
|
114
|
+
- textbox "Description (optional)" [ref=e192]
|
|
115
|
+
- generic [ref=e193]:
|
|
116
|
+
- generic [ref=e195]:
|
|
117
|
+
- checkbox "Bypass two-factor authentication (2FA) for this token" [checked] [ref=e196]
|
|
118
|
+
- generic [ref=e197]: Bypass two-factor authentication (2FA)
|
|
119
|
+
- paragraph [ref=e256]: There are security risks with this option. For automation or CI/CD uses, please use Trusted Publishing instead.
|
|
120
|
+
- group "Allowed IP ranges (optional) Must be valid CIDR notation." [ref=e198]:
|
|
121
|
+
- generic [ref=e199]:
|
|
122
|
+
- generic [ref=e200]: Allowed IP ranges (optional)
|
|
123
|
+
- caption [ref=e201]:
|
|
124
|
+
- text: Must be valid
|
|
125
|
+
- link "CIDR notation" [ref=e202] [cursor=pointer]:
|
|
126
|
+
- /url: https://docs.npmjs.com/creating-and-viewing-access-tokens/#cidr-restricted-token-errors
|
|
127
|
+
- text: .
|
|
128
|
+
- generic [ref=e204]:
|
|
129
|
+
- text: Input Range 1
|
|
130
|
+
- textbox "Input Range 1" [ref=e205]
|
|
131
|
+
- button "Add IP Range" [ref=e206]
|
|
132
|
+
- generic [ref=e207]:
|
|
133
|
+
- heading "Packages and scopes" [level=2] [ref=e208]
|
|
134
|
+
- generic [ref=e210]:
|
|
135
|
+
- paragraph [ref=e211]: Permissions
|
|
136
|
+
- group [ref=e212]:
|
|
137
|
+
- generic "Packages and scopes Permissions" [ref=e213] [cursor=pointer]:
|
|
138
|
+
- text: Read and write
|
|
139
|
+
- img [ref=e215]
|
|
140
|
+
- group "Select packages" [ref=e267]:
|
|
141
|
+
- generic [ref=e269]: Select packages
|
|
142
|
+
- generic [ref=e270]:
|
|
143
|
+
- generic [ref=e271]:
|
|
144
|
+
- radio "All packages" [checked] [ref=e273]
|
|
145
|
+
- generic [ref=e274]:
|
|
146
|
+
- text: All packages
|
|
147
|
+
- paragraph [ref=e275]: Applies to current and future packages.
|
|
148
|
+
- generic [ref=e276]:
|
|
149
|
+
- radio "Only select packages and scopes" [ref=e278]
|
|
150
|
+
- generic [ref=e279]:
|
|
151
|
+
- text: Only select packages and scopes
|
|
152
|
+
- paragraph [ref=e280]: Select at least one. Max 50.
|
|
153
|
+
- paragraph
|
|
154
|
+
- generic [ref=e218]:
|
|
155
|
+
- heading "Organizations" [level=2] [ref=e219]
|
|
156
|
+
- generic [ref=e221]:
|
|
157
|
+
- paragraph [ref=e222]: Permissions
|
|
158
|
+
- group [ref=e223]:
|
|
159
|
+
- generic "Organizations Permissions" [ref=e224] [cursor=pointer]:
|
|
160
|
+
- text: No access
|
|
161
|
+
- img [ref=e226]
|
|
162
|
+
- paragraph
|
|
163
|
+
- generic [ref=e229]:
|
|
164
|
+
- heading "Expiration" [level=2] [ref=e230]
|
|
165
|
+
- generic [ref=e232]:
|
|
166
|
+
- generic [ref=e233]: Expiration Date
|
|
167
|
+
- group [ref=e236]:
|
|
168
|
+
- generic "Expiration Date" [ref=e237] [cursor=pointer]:
|
|
169
|
+
- text: 90 days
|
|
170
|
+
- img [ref=e239]
|
|
171
|
+
- generic [ref=e242]:
|
|
172
|
+
- heading "Summary" [level=2] [ref=e243]
|
|
173
|
+
- generic [ref=e245]:
|
|
174
|
+
- paragraph [ref=e246]: "This token will:"
|
|
175
|
+
- list [ref=e247]:
|
|
176
|
+
- listitem [ref=e248]: Provide read and write access to all packages
|
|
177
|
+
- listitem [ref=e249]: Provide no access to organizations
|
|
178
|
+
- listitem [ref=e250]: Expires on Saturday, May 9, 2026
|
|
179
|
+
- generic [ref=e252]:
|
|
180
|
+
- button "Generate token" [ref=e253]
|
|
181
|
+
- button "Cancel" [ref=e254]
|
|
182
|
+
- contentinfo [ref=e123]:
|
|
183
|
+
- heading "Footer" [level=2] [ref=e124]
|
|
184
|
+
- generic [ref=e125]:
|
|
185
|
+
- generic [ref=e126]:
|
|
186
|
+
- link "Visit npm GitHub page" [ref=e128] [cursor=pointer]:
|
|
187
|
+
- /url: https://github.com/npm
|
|
188
|
+
- img [ref=e129]
|
|
189
|
+
- link "GitHub" [ref=e133] [cursor=pointer]:
|
|
190
|
+
- /url: https://github.com
|
|
191
|
+
- img [ref=e134]
|
|
192
|
+
- generic [ref=e136]:
|
|
193
|
+
- heading "Support" [level=3] [ref=e137]
|
|
194
|
+
- list "Support" [ref=e138]:
|
|
195
|
+
- listitem [ref=e139]:
|
|
196
|
+
- link "Help" [ref=e140] [cursor=pointer]:
|
|
197
|
+
- /url: https://docs.npmjs.com
|
|
198
|
+
- listitem [ref=e141]:
|
|
199
|
+
- link "Advisories" [ref=e142] [cursor=pointer]:
|
|
200
|
+
- /url: https://github.com/advisories
|
|
201
|
+
- listitem [ref=e143]:
|
|
202
|
+
- link "Status" [ref=e144] [cursor=pointer]:
|
|
203
|
+
- /url: http://status.npmjs.org/
|
|
204
|
+
- listitem [ref=e145]:
|
|
205
|
+
- link "Contact npm" [ref=e146] [cursor=pointer]:
|
|
206
|
+
- /url: /support
|
|
207
|
+
- generic [ref=e147]:
|
|
208
|
+
- heading "Company" [level=3] [ref=e148]
|
|
209
|
+
- list "Company" [ref=e149]:
|
|
210
|
+
- listitem [ref=e150]:
|
|
211
|
+
- link "About" [ref=e151] [cursor=pointer]:
|
|
212
|
+
- /url: /about
|
|
213
|
+
- listitem [ref=e152]:
|
|
214
|
+
- link "Blog" [ref=e153] [cursor=pointer]:
|
|
215
|
+
- /url: https://github.blog/tag/npm/
|
|
216
|
+
- listitem [ref=e154]:
|
|
217
|
+
- link "Press" [ref=e155] [cursor=pointer]:
|
|
218
|
+
- /url: /press
|
|
219
|
+
- generic [ref=e156]:
|
|
220
|
+
- heading "Terms & Policies" [level=3] [ref=e157]
|
|
221
|
+
- list "Terms & Policies" [ref=e158]:
|
|
222
|
+
- listitem [ref=e159]:
|
|
223
|
+
- link "Policies" [ref=e160] [cursor=pointer]:
|
|
224
|
+
- /url: /policies/
|
|
225
|
+
- listitem [ref=e161]:
|
|
226
|
+
- link "Terms of Use" [ref=e162] [cursor=pointer]:
|
|
227
|
+
- /url: /policies/terms
|
|
228
|
+
- listitem [ref=e163]:
|
|
229
|
+
- link "Code of Conduct" [ref=e164] [cursor=pointer]:
|
|
230
|
+
- /url: /policies/conduct
|
|
231
|
+
- listitem [ref=e165]:
|
|
232
|
+
- link "Privacy" [ref=e166] [cursor=pointer]:
|
|
233
|
+
- /url: /policies/privacy
|
|
234
|
+
- generic [ref=e168]: New Granular Access Token
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
- generic [active] [ref=e1]:
|
|
2
|
+
- generic [ref=e3]:
|
|
3
|
+
- region "Site notifications" [ref=e4]:
|
|
4
|
+
- generic [ref=e8]:
|
|
5
|
+
- generic [ref=e9]: ⚠️
|
|
6
|
+
- alert [ref=e11]:
|
|
7
|
+
- text: "Security Update: Classic tokens have been revoked. Granular tokens are now limited to 90 days and require 2FA by default. Update your CI/CD workflows to avoid disruption."
|
|
8
|
+
- link "Learn more about npm authentication changes" [ref=e12] [cursor=pointer]:
|
|
9
|
+
- /url: https://gh.io/all-npm-classic-tokens-revoked
|
|
10
|
+
- text: Learn more
|
|
11
|
+
- text: .
|
|
12
|
+
- button "Close notification" [ref=e13] [cursor=pointer]: ×
|
|
13
|
+
- generic [ref=e14]:
|
|
14
|
+
- banner [ref=e15]:
|
|
15
|
+
- generic [ref=e16]:
|
|
16
|
+
- generic [ref=e17]:
|
|
17
|
+
- text: "skip to:"
|
|
18
|
+
- link "skip to content" [ref=e18] [cursor=pointer]:
|
|
19
|
+
- /url: "#main"
|
|
20
|
+
- text: content
|
|
21
|
+
- link "skip to package search" [ref=e19] [cursor=pointer]:
|
|
22
|
+
- /url: "#search"
|
|
23
|
+
- text: package search
|
|
24
|
+
- generic [ref=e20]:
|
|
25
|
+
- generic [ref=e21]: ❤
|
|
26
|
+
- navigation "Product Navigation" [ref=e22]:
|
|
27
|
+
- list [ref=e23]:
|
|
28
|
+
- listitem [ref=e24]:
|
|
29
|
+
- link "Pro" [ref=e25] [cursor=pointer]:
|
|
30
|
+
- /url: /products/pro
|
|
31
|
+
- listitem [ref=e26]:
|
|
32
|
+
- link "Teams" [ref=e27] [cursor=pointer]:
|
|
33
|
+
- /url: /products/teams
|
|
34
|
+
- listitem [ref=e28]:
|
|
35
|
+
- link "Pricing" [ref=e29] [cursor=pointer]:
|
|
36
|
+
- /url: /products
|
|
37
|
+
- listitem [ref=e30]:
|
|
38
|
+
- link "Documentation" [ref=e31] [cursor=pointer]:
|
|
39
|
+
- /url: https://docs.npmjs.com
|
|
40
|
+
- generic [ref=e33]:
|
|
41
|
+
- generic [ref=e34]: npm
|
|
42
|
+
- link "Npm" [ref=e36] [cursor=pointer]:
|
|
43
|
+
- /url: /
|
|
44
|
+
- img [ref=e37]
|
|
45
|
+
- generic [ref=e40]:
|
|
46
|
+
- generic [ref=e42]:
|
|
47
|
+
- img [ref=e44]
|
|
48
|
+
- combobox "Search packages" [ref=e50]
|
|
49
|
+
- button "Search" [ref=e52]
|
|
50
|
+
- navigation [ref=e54]:
|
|
51
|
+
- button "Profile menu" [ref=e55]:
|
|
52
|
+
- generic [ref=e56]: Menu
|
|
53
|
+
- img [ref=e57]
|
|
54
|
+
- img [ref=e59]
|
|
55
|
+
- main [ref=e62]:
|
|
56
|
+
- generic [ref=e63]:
|
|
57
|
+
- complementary [ref=e64]:
|
|
58
|
+
- heading "Sidebar" [level=2] [ref=e65]
|
|
59
|
+
- generic [ref=e66]:
|
|
60
|
+
- navigation "Settings navigation" [ref=e67]:
|
|
61
|
+
- list [ref=e68]:
|
|
62
|
+
- listitem [ref=e69]:
|
|
63
|
+
- link "Profile" [ref=e70] [cursor=pointer]:
|
|
64
|
+
- /url: /~pedrohnas
|
|
65
|
+
- img [ref=e71]
|
|
66
|
+
- text: Profile
|
|
67
|
+
- listitem [ref=e73]:
|
|
68
|
+
- link "Packages" [ref=e74] [cursor=pointer]:
|
|
69
|
+
- /url: /settings/pedrohnas/packages
|
|
70
|
+
- img [ref=e75]
|
|
71
|
+
- text: Packages
|
|
72
|
+
- listitem [ref=e77]:
|
|
73
|
+
- link "Account" [ref=e78] [cursor=pointer]:
|
|
74
|
+
- /url: /settings/pedrohnas/profile
|
|
75
|
+
- img [ref=e79]
|
|
76
|
+
- text: Account
|
|
77
|
+
- listitem [ref=e81]:
|
|
78
|
+
- link "Billing Info" [ref=e82] [cursor=pointer]:
|
|
79
|
+
- /url: /settings/pedrohnas/billing
|
|
80
|
+
- img [ref=e83]
|
|
81
|
+
- text: Billing Info
|
|
82
|
+
- listitem [ref=e85]:
|
|
83
|
+
- link "Access Tokens" [ref=e86] [cursor=pointer]:
|
|
84
|
+
- /url: /settings/pedrohnas/tokens
|
|
85
|
+
- img [ref=e87]
|
|
86
|
+
- text: Access Tokens
|
|
87
|
+
- generic [ref=e89]:
|
|
88
|
+
- heading "Organizations" [level=3] [ref=e90]
|
|
89
|
+
- link "Create New Organization" [ref=e91] [cursor=pointer]:
|
|
90
|
+
- /url: /org/create
|
|
91
|
+
- text: +
|
|
92
|
+
- generic [ref=e92]: Create New Organization
|
|
93
|
+
- paragraph [ref=e93]: None
|
|
94
|
+
- generic [ref=e297]:
|
|
95
|
+
- generic [ref=e298]:
|
|
96
|
+
- generic [ref=e299]:
|
|
97
|
+
- heading "Access Tokens" [level=1] [ref=e300]
|
|
98
|
+
- link "Generate New Token" [ref=e302] [cursor=pointer]:
|
|
99
|
+
- /url: /settings/pedrohnas/tokens/granular-access-tokens/new
|
|
100
|
+
- button "Delete Selected Tokens" [ref=e304]
|
|
101
|
+
- generic [ref=e305]:
|
|
102
|
+
- alert [ref=e306]:
|
|
103
|
+
- paragraph [ref=e307]: Token successfully generated
|
|
104
|
+
- paragraph [ref=e308]: Make sure to copy your token. It will never be displayed again.
|
|
105
|
+
- paragraph [ref=e309]: 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
|
|
106
|
+
- generic [ref=e310]:
|
|
107
|
+
- textbox "Newly generated token" [ref=e311]: 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
|
|
108
|
+
- button "Copy" [ref=e312]:
|
|
109
|
+
- img [ref=e313]
|
|
110
|
+
- table [ref=e317]:
|
|
111
|
+
- rowgroup [ref=e318]:
|
|
112
|
+
- row "Select all Name Bypass 2FA Created Last used Expires Delete" [ref=e319]:
|
|
113
|
+
- columnheader "Select all" [ref=e320]:
|
|
114
|
+
- checkbox "Select all" [ref=e321]
|
|
115
|
+
- columnheader "Name" [ref=e322]
|
|
116
|
+
- columnheader "Bypass 2FA" [ref=e323]
|
|
117
|
+
- columnheader "Created" [ref=e324]
|
|
118
|
+
- columnheader "Last used" [ref=e325]
|
|
119
|
+
- columnheader "Expires" [ref=e326]
|
|
120
|
+
- columnheader "Delete" [ref=e327]:
|
|
121
|
+
- generic [ref=e328]: Delete
|
|
122
|
+
- rowgroup [ref=e329]:
|
|
123
|
+
- row "label for npm_VAaO......wJ41 opencode-telegram-publish npm_VAaO......wJ41 Feb 8, 2026 May 9, 2026 Delete token ending in wJ41" [ref=e330]:
|
|
124
|
+
- cell "label for npm_VAaO......wJ41" [ref=e331]:
|
|
125
|
+
- checkbox "label for npm_VAaO......wJ41" [ref=e332]
|
|
126
|
+
- cell "opencode-telegram-publish npm_VAaO......wJ41" [ref=e333]:
|
|
127
|
+
- generic [ref=e334]:
|
|
128
|
+
- link "opencode-telegram-publish" [ref=e335] [cursor=pointer]:
|
|
129
|
+
- /url: /settings/pedrohnas/tokens/granular-access-tokens/3aeafce1-5f79-45dc-a4fb-18c79567eb7f
|
|
130
|
+
- code [ref=e337]: npm_VAaO......wJ41
|
|
131
|
+
- cell [ref=e338]:
|
|
132
|
+
- img [ref=e340]
|
|
133
|
+
- cell "Feb 8, 2026" [ref=e342]:
|
|
134
|
+
- time [ref=e343]: Feb 8, 2026
|
|
135
|
+
- cell [ref=e344]
|
|
136
|
+
- cell "May 9, 2026" [ref=e345]:
|
|
137
|
+
- time [ref=e346]: May 9, 2026
|
|
138
|
+
- cell "Delete token ending in wJ41" [ref=e347]:
|
|
139
|
+
- button "Delete token ending in wJ41" [ref=e349] [cursor=pointer]: ×
|
|
140
|
+
- generic [ref=e352]: Rows 1 to 1 of 1
|
|
141
|
+
- paragraph [ref=e353]:
|
|
142
|
+
- link "📋 Read the Documentation" [ref=e354] [cursor=pointer]:
|
|
143
|
+
- /url: https://docs.npmjs.com/about-authentication-tokens
|
|
144
|
+
- contentinfo [ref=e123]:
|
|
145
|
+
- heading "Footer" [level=2] [ref=e124]
|
|
146
|
+
- generic [ref=e125]:
|
|
147
|
+
- generic [ref=e126]:
|
|
148
|
+
- link "Visit npm GitHub page" [ref=e128] [cursor=pointer]:
|
|
149
|
+
- /url: https://github.com/npm
|
|
150
|
+
- img [ref=e129]
|
|
151
|
+
- link "GitHub" [ref=e133] [cursor=pointer]:
|
|
152
|
+
- /url: https://github.com
|
|
153
|
+
- img [ref=e134]
|
|
154
|
+
- generic [ref=e136]:
|
|
155
|
+
- heading "Support" [level=3] [ref=e137]
|
|
156
|
+
- list "Support" [ref=e138]:
|
|
157
|
+
- listitem [ref=e139]:
|
|
158
|
+
- link "Help" [ref=e140] [cursor=pointer]:
|
|
159
|
+
- /url: https://docs.npmjs.com
|
|
160
|
+
- listitem [ref=e141]:
|
|
161
|
+
- link "Advisories" [ref=e142] [cursor=pointer]:
|
|
162
|
+
- /url: https://github.com/advisories
|
|
163
|
+
- listitem [ref=e143]:
|
|
164
|
+
- link "Status" [ref=e144] [cursor=pointer]:
|
|
165
|
+
- /url: http://status.npmjs.org/
|
|
166
|
+
- listitem [ref=e145]:
|
|
167
|
+
- link "Contact npm" [ref=e146] [cursor=pointer]:
|
|
168
|
+
- /url: /support
|
|
169
|
+
- generic [ref=e147]:
|
|
170
|
+
- heading "Company" [level=3] [ref=e148]
|
|
171
|
+
- list "Company" [ref=e149]:
|
|
172
|
+
- listitem [ref=e150]:
|
|
173
|
+
- link "About" [ref=e151] [cursor=pointer]:
|
|
174
|
+
- /url: /about
|
|
175
|
+
- listitem [ref=e152]:
|
|
176
|
+
- link "Blog" [ref=e153] [cursor=pointer]:
|
|
177
|
+
- /url: https://github.blog/tag/npm/
|
|
178
|
+
- listitem [ref=e154]:
|
|
179
|
+
- link "Press" [ref=e155] [cursor=pointer]:
|
|
180
|
+
- /url: /press
|
|
181
|
+
- generic [ref=e156]:
|
|
182
|
+
- heading "Terms & Policies" [level=3] [ref=e157]
|
|
183
|
+
- list "Terms & Policies" [ref=e158]:
|
|
184
|
+
- listitem [ref=e159]:
|
|
185
|
+
- link "Policies" [ref=e160] [cursor=pointer]:
|
|
186
|
+
- /url: /policies/
|
|
187
|
+
- listitem [ref=e161]:
|
|
188
|
+
- link "Terms of Use" [ref=e162] [cursor=pointer]:
|
|
189
|
+
- /url: /policies/terms
|
|
190
|
+
- listitem [ref=e163]:
|
|
191
|
+
- link "Code of Conduct" [ref=e164] [cursor=pointer]:
|
|
192
|
+
- /url: /policies/conduct
|
|
193
|
+
- listitem [ref=e165]:
|
|
194
|
+
- link "Privacy" [ref=e166] [cursor=pointer]:
|
|
195
|
+
- /url: /policies/privacy
|
|
196
|
+
- generic [ref=e168]: New Granular Access Token
|
package/docs/AUDIT.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Audit Report — OpenCode Telegram Bot vs OpenClaw Reference
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-02-08
|
|
4
|
+
**Scope:** Phases 0-6 complete, comparison against OpenClaw Telegram integration (~3,500 LOC, 41 files)
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. Project Stats
|
|
9
|
+
|
|
10
|
+
| Metric | Our Bot | OpenClaw |
|
|
11
|
+
|--------|---------|----------|
|
|
12
|
+
| Source LOC | 2,580 (21 files) | ~3,500 (41 files) |
|
|
13
|
+
| Unit tests | 252 | ~200+ (estimated) |
|
|
14
|
+
| E2E tests | 32 | Manual |
|
|
15
|
+
| Total LOC (incl tests + E2E) | ~7,000 | ~10,000+ |
|
|
16
|
+
| Architecture | SDK HTTP bridge | Direct agent integration |
|
|
17
|
+
| Framework | Grammy | Grammy |
|
|
18
|
+
| Runtime | Bun | Node.js |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 2. Quality Assessment by Phase
|
|
23
|
+
|
|
24
|
+
### Phases 0-4: Excellent
|
|
25
|
+
|
|
26
|
+
The core foundation is solid:
|
|
27
|
+
- **Anti-leak architecture** consistently applied (LRU, AbortController, bounded Maps)
|
|
28
|
+
- **TDD discipline** maintained — every file has colocated tests
|
|
29
|
+
- **EventBus** single SSE design is clean and memory-efficient
|
|
30
|
+
- **DraftStream** throttled editing works well
|
|
31
|
+
- **Permission/Question** handling with PendingRequests + inline keyboards is correct
|
|
32
|
+
- **Session management** with restore-on-restart is production-ready
|
|
33
|
+
|
|
34
|
+
### Phase 5 (Model & Agent Selection): Good
|
|
35
|
+
|
|
36
|
+
- Clean separation: `models.ts` (139 LOC) and `agents.ts` (93 LOC)
|
|
37
|
+
- Callback data fits 64-byte limit using direct IDs
|
|
38
|
+
- Override persistence across `/new` and session switches — properly fixed
|
|
39
|
+
- 28 unit tests + 9 E2E tests
|
|
40
|
+
- **Minor issue:** No pagination for providers with many models (deferred, acceptable)
|
|
41
|
+
|
|
42
|
+
### Phase 6 (Media & Files): Good
|
|
43
|
+
|
|
44
|
+
- Download/conversion pipeline is correct and well-tested
|
|
45
|
+
- MIME map is comprehensive (43 extensions)
|
|
46
|
+
- File size limit enforcement works
|
|
47
|
+
- DraftStream race condition properly fixed with `sending` flag
|
|
48
|
+
- 21 unit tests + 6 E2E tests (including fragmentation regression)
|
|
49
|
+
- **Minor issue:** `handleMedia` in bot.ts is an inline anonymous function, not exported for direct unit testing. It works via E2E tests, but differs from the pattern of other exported handlers.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 3. Production Gaps (vs OpenClaw)
|
|
54
|
+
|
|
55
|
+
### Critical — Should fix before production
|
|
56
|
+
|
|
57
|
+
| # | Gap | Impact | Effort |
|
|
58
|
+
|---|-----|--------|--------|
|
|
59
|
+
| **G1** | **EventBus has no auto-reconnect** | SSE stream break = bot stops receiving events silently. No exponential backoff. | Medium |
|
|
60
|
+
| **G2** | **No Grammy `apiThrottler()` middleware** | Telegram API 429 rate limits not handled. Under high load, API calls fail. | Low |
|
|
61
|
+
| **G3** | **No `sequentialize()` middleware** | Race conditions possible if Grammy processes concurrent updates for same chat (unlikely in polling mode, but risky with webhooks). | Low |
|
|
62
|
+
|
|
63
|
+
### Important — Should fix for robustness
|
|
64
|
+
|
|
65
|
+
| # | Gap | Impact | Effort |
|
|
66
|
+
|---|-----|--------|--------|
|
|
67
|
+
| **G4** | **No error classification** | Network errors (ECONNRESET, ETIMEDOUT) not distinguished from fatal errors. All treated the same. | Medium |
|
|
68
|
+
| **G5** | **EventBus `listen()` doesn't retry** | If the SSE stream ends (server restart, network issue), the bot goes deaf. No automatic reconnection. | Medium |
|
|
69
|
+
| **G6** | **No update deduplication** | Telegram can deliver duplicate updates. We process them again. | Low |
|
|
70
|
+
|
|
71
|
+
### Nice to have — For future phases
|
|
72
|
+
|
|
73
|
+
| # | Gap | Impact | Effort |
|
|
74
|
+
|---|-----|--------|--------|
|
|
75
|
+
| G7 | No text fragment assembly | Users who paste >4096 chars get each fragment processed separately | Medium |
|
|
76
|
+
| G8 | No media group buffering | Multi-photo sends = N separate prompts instead of one combined | Medium |
|
|
77
|
+
| G9 | No inbound debouncing | Rapid messages processed individually (can flood the AI) | Low |
|
|
78
|
+
| G10 | No sent-message cache | Can't deduplicate outbound messages | Low |
|
|
79
|
+
| G11 | No update offset persistence | Bot restart may re-process recent updates | Low |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 4. Code Structure Analysis
|
|
84
|
+
|
|
85
|
+
### Strengths
|
|
86
|
+
|
|
87
|
+
1. **Clean module boundaries** — Each handler file is self-contained with pure functions + async handlers
|
|
88
|
+
2. **Dependency injection** — `DraftStreamDeps`, `BotDeps`, SDK as params (not globals)
|
|
89
|
+
3. **Testability** — Every handler can be tested without Grammy context
|
|
90
|
+
4. **Anti-leak guarantees** — AbortController per turn, LRU bounded SessionManager, TTL on PendingRequests
|
|
91
|
+
5. **Session restore** — Bot survives restarts by matching "Telegram {chatId}" title pattern
|
|
92
|
+
|
|
93
|
+
### Areas for Improvement
|
|
94
|
+
|
|
95
|
+
1. **`bot.ts` is growing** (479 LOC) — Approaching the split threshold. Consider extracting:
|
|
96
|
+
- Callback routing → `handlers/callbacks.ts`
|
|
97
|
+
- `handleMedia` → export from `handlers/media.ts` for testability
|
|
98
|
+
- `handleMessage` is already well-structured
|
|
99
|
+
|
|
100
|
+
2. **`index.ts` does too much** (283 LOC) — Event routing and `finalizeResponse` live in the entry point. Should be in a dedicated `event-router.ts` for unit testability.
|
|
101
|
+
|
|
102
|
+
3. **Event types are `any`** — EventBus uses `any` for event types. Type-safe event handling would catch bugs at compile time.
|
|
103
|
+
|
|
104
|
+
4. **No structured logging** — All errors go to `console.error`. No log levels, no structured format, no error context.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 5. What We Do Better Than OpenClaw
|
|
109
|
+
|
|
110
|
+
| Aspect | Our Advantage |
|
|
111
|
+
|--------|--------------|
|
|
112
|
+
| **Architecture** | SDK bridge is thinner (~2,580 LOC vs ~3,500). Delegates AI complexity to server. |
|
|
113
|
+
| **Testing** | 252 unit + 32 E2E with TDD rigor. Phase-gated with full regression at each step. |
|
|
114
|
+
| **Memory safety** | Explicit anti-leak design: LRU, AbortController, bounded everything. |
|
|
115
|
+
| **Deployment** | Simple env vars (4-5 vars). No YAML config, no multi-account, no pairing system. |
|
|
116
|
+
| **Session management** | Server-side persistence with local LRU cache. Clean restore on restart. |
|
|
117
|
+
| **Phase gating** | Clear boundaries, docs per phase, regression testing. Sustainable development. |
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 6. Feature Parity Matrix
|
|
122
|
+
|
|
123
|
+
| Feature | Our Bot | OpenClaw | Notes |
|
|
124
|
+
|---------|---------|----------|-------|
|
|
125
|
+
| Text messages | ✅ | ✅ | |
|
|
126
|
+
| Photo/Document/Audio/Video | ✅ | ✅ | Phase 6 |
|
|
127
|
+
| Voice messages | ✅ | ✅ | |
|
|
128
|
+
| Streaming (edit draft) | ✅ | ✅ | With `sending` fix |
|
|
129
|
+
| Permissions (inline buttons) | ✅ | N/A | OpenClaw has no permission system |
|
|
130
|
+
| Questions (inline buttons) | ✅ | N/A | OpenClaw has no question system |
|
|
131
|
+
| /cancel (abort) | ✅ | ✅ | |
|
|
132
|
+
| Session management | ✅ | ✅ | /list, /rename, /delete, /info, /history |
|
|
133
|
+
| Session restore on restart | ✅ | ✅ | Title pattern matching |
|
|
134
|
+
| Model selection | ✅ | ✅ | Phase 5 |
|
|
135
|
+
| Agent selection | ✅ | N/A | OpenClaw has different agent system |
|
|
136
|
+
| Allowlist | ✅ | ✅ | |
|
|
137
|
+
| Markdown → HTML | ✅ | ✅ | |
|
|
138
|
+
| Message chunking | ✅ | ✅ | |
|
|
139
|
+
| HTML fallback | ✅ | ✅ | |
|
|
140
|
+
| Typing indicator | ✅ | ✅ | |
|
|
141
|
+
| Tool progress | ✅ | N/A | |
|
|
142
|
+
| Auto-reconnect SSE | ❌ | ✅ | **Gap G1/G5** |
|
|
143
|
+
| Rate limit middleware | ❌ | ✅ | **Gap G2** |
|
|
144
|
+
| Sequentialize middleware | ❌ | ✅ | **Gap G3** |
|
|
145
|
+
| Text fragment assembly | ❌ | ✅ | Gap G7 |
|
|
146
|
+
| Media group buffering | ❌ | ✅ | Gap G8 |
|
|
147
|
+
| Inbound debouncing | ❌ | ✅ | Gap G9 |
|
|
148
|
+
| Group chat support | ❌ | ✅ | Phase 8 planned |
|
|
149
|
+
| Forum topics | ❌ | ✅ | Phase 8 planned |
|
|
150
|
+
| Webhook mode | ❌ | ✅ | Phase 9 planned |
|
|
151
|
+
| Sticker vision cache | ❌ | ✅ | Nice to have |
|
|
152
|
+
| Voice → voice bubble | ❌ | ✅ | Nice to have |
|
|
153
|
+
| Multi-account | ❌ | ✅ | Not needed |
|
|
154
|
+
| Audit logging | ❌ | ✅ | Not needed |
|
|
155
|
+
| Update offset persistence | ❌ | ✅ | Gap G11 |
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 7. Recommendations
|
|
160
|
+
|
|
161
|
+
### Before Production (Priority)
|
|
162
|
+
|
|
163
|
+
1. **Fix EventBus reconnection (G1+G5)** — Add exponential backoff loop in `listen()`. When SSE stream ends or errors, wait 2s→30s (1.8x factor) and reconnect. This is the most critical gap.
|
|
164
|
+
|
|
165
|
+
2. **Add `apiThrottler()` (G2)** — One line of Grammy middleware. Prevents 429 errors.
|
|
166
|
+
|
|
167
|
+
3. **Add `sequentialize()` (G3)** — One line of Grammy middleware. Prevents per-chat race conditions (important if switching to webhooks later).
|
|
168
|
+
|
|
169
|
+
### Before Phase 7 (Recommended)
|
|
170
|
+
|
|
171
|
+
4. **Extract event routing from index.ts** — Move `onEvent` callback and `finalizeResponse` to `event-router.ts`. Enables unit testing of event logic.
|
|
172
|
+
|
|
173
|
+
5. **Type SSE events** — Replace `any` with typed event union in EventBus.
|
|
174
|
+
|
|
175
|
+
### For Future Phases
|
|
176
|
+
|
|
177
|
+
6. **Text fragment assembly (G7)** — Buffer near-limit messages for 1500ms, merge.
|
|
178
|
+
7. **Media group buffering (G8)** — Buffer same `media_group_id` for 200ms.
|
|
179
|
+
8. **Inbound debouncing (G9)** — 300-500ms buffer for rapid messages.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 8. Overall Assessment
|
|
184
|
+
|
|
185
|
+
**The codebase quality is good.** Phases 5 and 6 maintained the same standards as earlier phases:
|
|
186
|
+
- Clean module boundaries
|
|
187
|
+
- Comprehensive test coverage
|
|
188
|
+
- Anti-leak design throughout
|
|
189
|
+
- Bugs found via manual testing were properly diagnosed and fixed with tests
|
|
190
|
+
|
|
191
|
+
**The main gaps are infrastructure-level** (reconnection, rate limiting, middleware), not code quality issues. These are expected at the Phase 6 stage and should be addressed in Phase 9 (Infrastructure & Security) or as a hardening pass before production deployment.
|
|
192
|
+
|
|
193
|
+
**LOC target from spec was ~2,000 for Phase 1.** At Phase 6 we're at 2,580 for all source — well within the expected trajectory toward the spec's full target.
|