@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.
Files changed (39) hide show
  1. package/.claude/skills/playwright-cli/data/page-2026-02-09T02-40-45-070Z.png +0 -0
  2. package/.claude/skills/playwright-cli/data/page-2026-02-09T02-41-15-698Z.yml +168 -0
  3. package/.claude/skills/playwright-cli/data/page-2026-02-09T02-41-25-514Z.yml +219 -0
  4. package/.claude/skills/playwright-cli/data/page-2026-02-09T02-41-40-888Z.yml +221 -0
  5. package/.claude/skills/playwright-cli/data/page-2026-02-09T02-41-46-079Z.yml +230 -0
  6. package/.claude/skills/playwright-cli/data/page-2026-02-09T02-41-53-985Z.yml +235 -0
  7. package/.claude/skills/playwright-cli/data/page-2026-02-09T02-42-03-227Z.yml +235 -0
  8. package/.claude/skills/playwright-cli/data/page-2026-02-09T02-42-08-587Z.yml +248 -0
  9. package/.claude/skills/playwright-cli/data/page-2026-02-09T02-42-16-524Z.yml +234 -0
  10. package/.claude/skills/playwright-cli/data/page-2026-02-09T02-42-26-086Z.yml +196 -0
  11. package/docs/AUDIT.md +193 -0
  12. package/docs/PROGRESS.md +191 -0
  13. package/docs/plans/phase-5.md +410 -0
  14. package/docs/plans/phase-6.5.md +426 -0
  15. package/docs/plans/phase-6.md +349 -0
  16. package/e2e/helpers.ts +34 -0
  17. package/e2e/phase-5.test.ts +295 -0
  18. package/e2e/phase-6.5.test.ts +239 -0
  19. package/e2e/phase-6.test.ts +302 -0
  20. package/package.json +5 -2
  21. package/src/api-server.test.ts +309 -0
  22. package/src/api-server.ts +201 -0
  23. package/src/bot.test.ts +354 -0
  24. package/src/bot.ts +200 -2
  25. package/src/config.test.ts +16 -0
  26. package/src/config.ts +4 -0
  27. package/src/event-bus.test.ts +337 -1
  28. package/src/event-bus.ts +83 -3
  29. package/src/handlers/agents.test.ts +122 -0
  30. package/src/handlers/agents.ts +93 -0
  31. package/src/handlers/media.test.ts +264 -0
  32. package/src/handlers/media.ts +168 -0
  33. package/src/handlers/models.test.ts +319 -0
  34. package/src/handlers/models.ts +191 -0
  35. package/src/index.ts +15 -0
  36. package/src/send/draft-stream.test.ts +76 -0
  37. package/src/send/draft-stream.ts +13 -1
  38. package/src/session-manager.test.ts +46 -0
  39. 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.