paperclip-plugin-telegram 0.3.0 → 0.5.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.tsx"],"names":[],"mappings":"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"}
package/dist/worker.js CHANGED
@@ -1,14 +1,125 @@
1
1
  import { definePlugin, runWorker, } from "@paperclipai/plugin-sdk";
2
2
  import { sendMessage, editMessage, answerCallbackQuery, setMyCommands, escapeMarkdownV2, isForum, GENERAL_TOPIC_THREAD_ID, } from "./telegram-api.js";
3
- import { formatIssueCreated, formatIssueDone, formatApprovalCreated, formatAgentError, formatAgentRunStarted, formatAgentRunFinished, } from "./formatters.js";
4
- import { handleCommand, getTopicForProject, BOT_COMMANDS } from "./commands.js";
3
+ import { formatIssueCreated, formatIssueDone, formatIssueAssigned, formatApprovalCreated, formatAgentError, formatAgentRunStarted, formatAgentRunFinished, } from "./formatters.js";
4
+ import { handleCommand, resolveNotificationThreadId, BOT_COMMANDS } from "./commands.js";
5
5
  import { routeMessageToAgent, handleHandoffToolCall, handleDiscussToolCall, handleHandoffApproval, handleHandoffRejection, setupAcpOutputListener, } from "./acp-bridge.js";
6
6
  import { handleMediaMessage } from "./media-pipeline.js";
7
+ import { getPersistedTelegramUpdateOffset, persistTelegramUpdateOffset } from "./polling-offset.js";
7
8
  import { handleCommandsCommand, tryCustomCommand } from "./command-registry.js";
8
9
  import { handleRegisterWatch, checkWatches } from "./watch-registry.js";
9
10
  import { METRIC_NAMES } from "./constants.js";
10
11
  import { EscalationManager } from "./escalation.js";
12
+ import { isTelegramUpdateAllowed, validateTelegramAllowlists } from "./allowlist.js";
13
+ import { shouldNotifyApproval } from "./approval-routing.js";
14
+ import { buildPaperclipAuthHeaders, fetchPaperclipApi } from "./paperclip-api.js";
11
15
  const TELEGRAM_API = "https://api.telegram.org";
16
+ const BOARD_ACCESS_SCOPE = {
17
+ scopeKind: "instance",
18
+ stateKey: "telegram.board-access.v1",
19
+ };
20
+ function isRecord(value) {
21
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22
+ }
23
+ function asNonEmptyString(value) {
24
+ return typeof value === "string" && value.trim() ? value.trim() : null;
25
+ }
26
+ function normalizeBoardAccessState(value) {
27
+ const record = isRecord(value) ? value : {};
28
+ return {
29
+ paperclipBoardApiTokenRef: asNonEmptyString(record.paperclipBoardApiTokenRef),
30
+ identity: asNonEmptyString(record.identity),
31
+ companyId: asNonEmptyString(record.companyId),
32
+ updatedAt: asNonEmptyString(record.updatedAt),
33
+ };
34
+ }
35
+ async function loadBoardAccessState(ctx) {
36
+ return normalizeBoardAccessState(await ctx.state.get(BOARD_ACCESS_SCOPE));
37
+ }
38
+ async function persistBoardAccessState(ctx, state) {
39
+ const nextState = normalizeBoardAccessState(state);
40
+ await ctx.state.set(BOARD_ACCESS_SCOPE, nextState);
41
+ return {
42
+ ...nextState,
43
+ configured: Boolean(nextState.paperclipBoardApiTokenRef),
44
+ };
45
+ }
46
+ function getBoardAccessRegistration(state) {
47
+ return {
48
+ ...state,
49
+ configured: Boolean(state.paperclipBoardApiTokenRef),
50
+ };
51
+ }
52
+ async function resolveBoardApiToken(ctx, config, companyId) {
53
+ const boardAccessState = await loadBoardAccessState(ctx);
54
+ const candidates = [];
55
+ if (boardAccessState.paperclipBoardApiTokenRef &&
56
+ (!companyId || !boardAccessState.companyId || boardAccessState.companyId === companyId)) {
57
+ candidates.push({
58
+ source: "board-access",
59
+ ref: boardAccessState.paperclipBoardApiTokenRef,
60
+ });
61
+ }
62
+ if (config.paperclipBoardApiTokenRef) {
63
+ candidates.push({
64
+ source: "config",
65
+ ref: config.paperclipBoardApiTokenRef,
66
+ });
67
+ }
68
+ const seen = new Set();
69
+ for (const candidate of candidates) {
70
+ if (seen.has(candidate.ref))
71
+ continue;
72
+ seen.add(candidate.ref);
73
+ try {
74
+ return await ctx.secrets.resolve(candidate.ref);
75
+ }
76
+ catch (err) {
77
+ ctx.logger.warn("Failed to resolve board API token secret", {
78
+ source: candidate.source,
79
+ companyId,
80
+ error: String(err),
81
+ });
82
+ }
83
+ }
84
+ return undefined;
85
+ }
86
+ async function resolveCallbackCompanyId(ctx, query) {
87
+ const chatId = query.message?.chat.id ? String(query.message.chat.id) : null;
88
+ const messageId = query.message?.message_id;
89
+ if (!chatId || !messageId)
90
+ return null;
91
+ const mapping = await ctx.state.get({
92
+ scopeKind: "instance",
93
+ stateKey: `msg_${chatId}_${messageId}`,
94
+ });
95
+ return mapping?.companyId ?? null;
96
+ }
97
+ /**
98
+ * Shared 5s sliding-window dedupe for issue.updated handlers.
99
+ *
100
+ * Paperclip's core can emit duplicate `issue.updated` plugin events for a
101
+ * single PATCH (the route's logActivity plus side-effects from heartbeat
102
+ * reconciliation), so handlers must dedupe to avoid sending the same
103
+ * Telegram message twice.
104
+ */
105
+ function makeUpdateDedupe(windowMs = 5_000, maxEntries = 500) {
106
+ const seen = new Map();
107
+ return (key) => {
108
+ const now = Date.now();
109
+ const last = seen.get(key);
110
+ if (last !== undefined && now - last < windowMs)
111
+ return false;
112
+ seen.set(key, now);
113
+ if (seen.size > maxEntries) {
114
+ const cutoff = now - windowMs;
115
+ for (const [k, ts] of seen) {
116
+ if (ts < cutoff)
117
+ seen.delete(k);
118
+ }
119
+ }
120
+ return true;
121
+ };
122
+ }
12
123
  async function resolveChat(ctx, companyId, fallback) {
13
124
  const override = await ctx.state.get({
14
125
  scopeKind: "company",
@@ -17,6 +128,32 @@ async function resolveChat(ctx, companyId, fallback) {
17
128
  });
18
129
  return override ?? fallback ?? null;
19
130
  }
131
+ function parseTopicId(value) {
132
+ const trimmed = value?.trim();
133
+ if (!trimmed)
134
+ return undefined;
135
+ if (!/^\d+$/.test(trimmed))
136
+ return undefined;
137
+ return Number(trimmed);
138
+ }
139
+ function validateConfiguredTopicIds(config) {
140
+ const errors = [];
141
+ for (const key of ["approvalsTopicId", "errorsTopicId", "digestTopicId"]) {
142
+ const value = config[key];
143
+ if (value === undefined || value === null || value === "")
144
+ continue;
145
+ if (typeof value !== "string" || !parseTopicId(value)) {
146
+ errors.push(`${key} must be a numeric Telegram forum topic ID string.`);
147
+ }
148
+ }
149
+ return errors;
150
+ }
151
+ async function resolveDigestThreadId(ctx, token, chatId, configuredTopicId) {
152
+ const configured = parseTopicId(configuredTopicId);
153
+ if (configured)
154
+ return configured;
155
+ return await isForum(ctx, token, chatId) ? GENERAL_TOPIC_THREAD_ID : undefined;
156
+ }
20
157
  async function resolveCompanyId(ctx, chatId) {
21
158
  const mapping = await ctx.state.get({
22
159
  scopeKind: "instance",
@@ -31,6 +168,20 @@ const plugin = definePlugin({
31
168
  const config = rawConfig;
32
169
  const baseUrl = config.paperclipBaseUrl || "http://localhost:3100";
33
170
  const publicUrl = config.paperclipPublicUrl || baseUrl;
171
+ ctx.data.register("board-access.read", async () => getBoardAccessRegistration(await loadBoardAccessState(ctx)));
172
+ ctx.actions.register("board-access.update", async (params) => {
173
+ const record = isRecord(params) ? params : {};
174
+ const paperclipBoardApiTokenRef = asNonEmptyString(record.paperclipBoardApiTokenRef);
175
+ const identity = asNonEmptyString(record.identity);
176
+ const companyId = asNonEmptyString(record.companyId);
177
+ const now = new Date().toISOString();
178
+ return persistBoardAccessState(ctx, {
179
+ paperclipBoardApiTokenRef,
180
+ identity,
181
+ companyId,
182
+ updatedAt: now,
183
+ });
184
+ });
34
185
  if (!config.telegramBotTokenRef) {
35
186
  ctx.logger.warn("No telegramBotTokenRef configured, plugin disabled");
36
187
  return;
@@ -60,7 +211,7 @@ const plugin = definePlugin({
60
211
  }
61
212
  // --- Long polling for inbound messages ---
62
213
  let pollingActive = true;
63
- let lastUpdateId = 0;
214
+ let lastUpdateId = await getPersistedTelegramUpdateOffset(ctx);
64
215
  async function pollUpdates() {
65
216
  while (pollingActive) {
66
217
  try {
@@ -68,8 +219,28 @@ const plugin = definePlugin({
68
219
  const data = (await res.json());
69
220
  if (data.ok && data.result) {
70
221
  for (const update of data.result) {
71
- lastUpdateId = Math.max(lastUpdateId, update.update_id);
72
- await handleUpdate(ctx, token, config, update, baseUrl, publicUrl);
222
+ try {
223
+ await handleUpdate(ctx, token, config, update, baseUrl, publicUrl);
224
+ }
225
+ catch (err) {
226
+ ctx.logger.error("Telegram update handling failed", {
227
+ updateId: update.update_id,
228
+ error: String(err),
229
+ });
230
+ }
231
+ const nextUpdateId = Math.max(lastUpdateId, update.update_id);
232
+ if (nextUpdateId > lastUpdateId) {
233
+ lastUpdateId = nextUpdateId;
234
+ try {
235
+ await persistTelegramUpdateOffset(ctx, lastUpdateId);
236
+ }
237
+ catch (err) {
238
+ ctx.logger.error("Failed to persist Telegram polling offset", {
239
+ updateId: lastUpdateId,
240
+ error: String(err),
241
+ });
242
+ }
243
+ }
73
244
  }
74
245
  }
75
246
  }
@@ -99,25 +270,35 @@ const plugin = definePlugin({
99
270
  }
100
271
  return { baseUrl: publicUrl, issuePrefix: prefix || undefined };
101
272
  }
102
- const notify = async (event, formatter, overrideChatId) => {
273
+ const notify = async (event, formatter, overrideChatId, overrideTopicId) => {
103
274
  const chatId = await resolveChat(ctx, event.companyId, overrideChatId || config.defaultChatId);
104
275
  if (!chatId)
105
276
  return;
106
277
  const linksOpts = await resolveIssueLinksOpts(event.companyId);
107
278
  const msg = formatter(event, linksOpts);
108
- let messageThreadId;
109
- if (config.topicRouting) {
110
- const payload = event.payload;
111
- const projectName = payload.projectName ? String(payload.projectName) : undefined;
112
- messageThreadId = await getTopicForProject(ctx, chatId, projectName);
113
- }
114
- // For forum groups, fall back to General topic if no specific topic mapping
115
- if (!messageThreadId && await isForum(ctx, token, chatId)) {
116
- messageThreadId = GENERAL_TOPIC_THREAD_ID;
279
+ let messageThreadId = parseTopicId(overrideTopicId);
280
+ if (!messageThreadId) {
281
+ messageThreadId = await resolveNotificationThreadId(ctx, chatId, event, config.topicRouting);
117
282
  }
118
283
  if (messageThreadId) {
119
284
  msg.options.messageThreadId = messageThreadId;
120
285
  }
286
+ // Issue threading — if we've already sent a message for this entity in this
287
+ // chat+topic, reply to that anchor so all updates about a single entity stack
288
+ // as one Telegram thread on mobile (created → comments → done).
289
+ const anchorKey = event.entityId
290
+ ? `anchor_${chatId}_${event.entityType}_${event.entityId}`
291
+ : null;
292
+ if (anchorKey) {
293
+ const anchor = (await ctx.state.get({
294
+ scopeKind: "instance",
295
+ stateKey: anchorKey,
296
+ }));
297
+ // Only thread when targeting the same topic — Telegram rejects cross-topic replies.
298
+ if (anchor?.messageId && anchor.messageThreadId === messageThreadId) {
299
+ msg.options.replyToMessageId = anchor.messageId;
300
+ }
301
+ }
121
302
  const messageId = await sendMessage(ctx, token, chatId, msg.text, msg.options);
122
303
  if (messageId) {
123
304
  await ctx.state.set({
@@ -135,16 +316,30 @@ const plugin = definePlugin({
135
316
  entityType: "plugin",
136
317
  entityId: event.entityId,
137
318
  });
319
+ // First-message-per-entity: store the anchor so future notifications about the
320
+ // same entity reply to this one. Never overwritten — the first message stays root.
321
+ if (anchorKey) {
322
+ const existing = (await ctx.state.get({
323
+ scopeKind: "instance",
324
+ stateKey: anchorKey,
325
+ }));
326
+ if (!existing) {
327
+ await ctx.state.set({ scopeKind: "instance", stateKey: anchorKey }, { messageId, messageThreadId });
328
+ }
329
+ }
138
330
  }
139
331
  };
140
332
  if (config.notifyOnIssueCreated) {
141
333
  ctx.events.on("issue.created", (event) => notify(event, formatIssueCreated));
142
334
  }
143
335
  if (config.notifyOnIssueDone) {
336
+ const doneDedupe = makeUpdateDedupe();
144
337
  ctx.events.on("issue.updated", async (event) => {
145
338
  const payload = event.payload;
146
339
  if (payload.status !== "done")
147
340
  return;
341
+ if (!doneDedupe(`done|${event.entityId}`))
342
+ return;
148
343
  // Enrich with title if missing (issue.updated events often omit it)
149
344
  if (!payload.title && event.entityId) {
150
345
  try {
@@ -168,8 +363,47 @@ const plugin = definePlugin({
168
363
  await notify(event, formatIssueDone);
169
364
  });
170
365
  }
366
+ if (config.notifyOnIssueAssigned) {
367
+ const assignmentDedupe = makeUpdateDedupe();
368
+ ctx.events.on("issue.updated", async (event) => {
369
+ const payload = event.payload;
370
+ const prev = payload._previous ?? {};
371
+ const userChanged = "assigneeUserId" in payload && payload.assigneeUserId !== prev.assigneeUserId;
372
+ const agentChanged = "assigneeAgentId" in payload && payload.assigneeAgentId !== prev.assigneeAgentId;
373
+ if (!userChanged && !agentChanged)
374
+ return;
375
+ if (config.onlyNotifyIfAssignedTo && payload.assigneeUserId !== config.onlyNotifyIfAssignedTo) {
376
+ return;
377
+ }
378
+ const dedupeKey = [
379
+ "assigned",
380
+ event.entityId,
381
+ String(prev.assigneeUserId ?? ""),
382
+ String(payload.assigneeUserId ?? ""),
383
+ String(prev.assigneeAgentId ?? ""),
384
+ String(payload.assigneeAgentId ?? ""),
385
+ ].join("|");
386
+ if (!assignmentDedupe(dedupeKey))
387
+ return;
388
+ if ((!payload.title || !payload.assigneeName) && event.entityId) {
389
+ try {
390
+ const issue = await ctx.issues.get(event.entityId, event.companyId);
391
+ if (issue) {
392
+ payload.title ??= issue.title;
393
+ const name = issue.assigneeName;
394
+ if (name)
395
+ payload.assigneeName ??= name;
396
+ }
397
+ }
398
+ catch { /* best effort */ }
399
+ }
400
+ await notify(event, formatIssueAssigned);
401
+ });
402
+ }
171
403
  if (config.notifyOnApprovalCreated) {
172
404
  ctx.events.on("approval.created", async (event) => {
405
+ if (!shouldNotifyApproval(event, config.onlyNotifyBoardApprovals))
406
+ return;
173
407
  const payload = event.payload;
174
408
  // Enrich with linked issue details (event only has issueIds)
175
409
  const issueIds = Array.isArray(payload.issueIds) ? payload.issueIds : [];
@@ -210,11 +444,11 @@ const plugin = definePlugin({
210
444
  ? `${approvalType} — ${agentLabel}`
211
445
  : approvalType;
212
446
  }
213
- await notify(event, formatApprovalCreated, config.approvalsChatId);
447
+ await notify(event, formatApprovalCreated, config.approvalsChatId, config.approvalsTopicId);
214
448
  });
215
449
  }
216
450
  if (config.notifyOnAgentError) {
217
- ctx.events.on("agent.run.failed", (event) => notify(event, formatAgentError, config.errorsChatId));
451
+ ctx.events.on("agent.run.failed", (event) => notify(event, formatAgentError, config.errorsChatId, config.errorsTopicId));
218
452
  }
219
453
  ctx.events.on("agent.run.started", (event) => notify(event, formatAgentRunStarted));
220
454
  ctx.events.on("agent.run.finished", (event) => notify(event, formatAgentRunFinished));
@@ -270,7 +504,7 @@ const plugin = definePlugin({
270
504
  return;
271
505
  const companies = await ctx.companies.list();
272
506
  for (const company of companies) {
273
- const chatId = await resolveChat(ctx, company.id, config.defaultChatId);
507
+ const chatId = await resolveChat(ctx, company.id, config.digestChatId || config.defaultChatId);
274
508
  if (!chatId)
275
509
  continue;
276
510
  try {
@@ -321,9 +555,7 @@ const plugin = definePlugin({
321
555
  for (const i of blocked.slice(0, 10))
322
556
  lines.push(formatIssueItem(i));
323
557
  }
324
- const digestThreadId = await isForum(ctx, token, chatId)
325
- ? GENERAL_TOPIC_THREAD_ID
326
- : undefined;
558
+ const digestThreadId = await resolveDigestThreadId(ctx, token, chatId, config.digestTopicId);
327
559
  await sendMessage(ctx, token, chatId, lines.join("\n"), {
328
560
  parseMode: "MarkdownV2",
329
561
  messageThreadId: digestThreadId,
@@ -336,9 +568,7 @@ const plugin = definePlugin({
336
568
  "",
337
569
  escapeMarkdownV2("Could not generate digest. Check plugin logs for details."),
338
570
  ].join("\n");
339
- const errorThreadId = await isForum(ctx, token, chatId)
340
- ? GENERAL_TOPIC_THREAD_ID
341
- : undefined;
571
+ const errorThreadId = await resolveDigestThreadId(ctx, token, chatId, config.errorsTopicId || config.digestTopicId);
342
572
  await sendMessage(ctx, token, chatId, text, {
343
573
  parseMode: "MarkdownV2",
344
574
  messageThreadId: errorThreadId,
@@ -531,15 +761,35 @@ const plugin = definePlugin({
531
761
  if (!config.telegramBotTokenRef || typeof config.telegramBotTokenRef !== "string") {
532
762
  return { ok: false, errors: ["telegramBotTokenRef is required"] };
533
763
  }
764
+ const allowlistErrors = validateTelegramAllowlists(config);
765
+ if (allowlistErrors.length > 0) {
766
+ return { ok: false, errors: allowlistErrors };
767
+ }
768
+ const topicErrors = validateConfiguredTopicIds(config);
769
+ if (topicErrors.length > 0) {
770
+ return { ok: false, errors: topicErrors };
771
+ }
534
772
  return { ok: true };
535
773
  },
536
774
  async onHealth() {
537
775
  return { status: "ok" };
538
776
  },
539
777
  });
540
- async function handleUpdate(ctx, token, config, update, baseUrl, publicUrl) {
778
+ async function handleUpdate(ctx, token, config, update, baseUrl, publicUrl, boardApiToken) {
779
+ if (!isTelegramUpdateAllowed(config, update)) {
780
+ const fromId = update.message?.from?.id ?? update.callback_query?.from.id;
781
+ const chatId = update.message?.chat.id ?? update.callback_query?.message?.chat.id;
782
+ ctx.logger.warn("Blocked unauthorized Telegram update", {
783
+ updateId: update.update_id,
784
+ fromId,
785
+ chatId,
786
+ });
787
+ return;
788
+ }
541
789
  if (update.callback_query) {
542
- await handleCallbackQuery(ctx, token, update.callback_query, baseUrl);
790
+ const companyId = await resolveCallbackCompanyId(ctx, update.callback_query);
791
+ const boardApiToken = await resolveBoardApiToken(ctx, config, companyId);
792
+ await handleCallbackQuery(ctx, token, update.callback_query, baseUrl, boardApiToken);
543
793
  return;
544
794
  }
545
795
  const msg = update.message;
@@ -589,7 +839,8 @@ async function handleUpdate(ctx, token, config, update, baseUrl, publicUrl) {
589
839
  if (handledCustom)
590
840
  return;
591
841
  // Built-in commands
592
- await handleCommand(ctx, token, chatId, command, args, threadId, baseUrl, publicUrl);
842
+ const boardApiToken = command === "approve" ? await resolveBoardApiToken(ctx, config, companyId) : undefined;
843
+ await handleCommand(ctx, token, chatId, command, args, threadId, baseUrl, publicUrl, companyId, boardApiToken);
593
844
  return;
594
845
  }
595
846
  if (config.enableInbound && msg.reply_to_message?.from?.is_bot) {
@@ -634,7 +885,7 @@ async function handleUpdate(ctx, token, config, update, baseUrl, publicUrl) {
634
885
  }
635
886
  }
636
887
  }
637
- async function handleCallbackQuery(ctx, token, query, baseUrl) {
888
+ async function handleCallbackQuery(ctx, token, query, baseUrl, boardApiToken) {
638
889
  const data = query.data;
639
890
  if (!data)
640
891
  return;
@@ -645,9 +896,12 @@ async function handleCallbackQuery(ctx, token, query, baseUrl) {
645
896
  const approvalId = data.replace("approve_", "");
646
897
  ctx.logger.info("Approval button clicked", { approvalId, actor });
647
898
  try {
648
- await ctx.http.fetch(`${baseUrl}/api/approvals/${approvalId}/approve`, {
899
+ await fetchPaperclipApi(ctx, `${baseUrl}/api/approvals/${approvalId}/approve`, {
649
900
  method: "POST",
650
- headers: { "Content-Type": "application/json" },
901
+ headers: {
902
+ "Content-Type": "application/json",
903
+ ...buildPaperclipAuthHeaders(boardApiToken),
904
+ },
651
905
  body: JSON.stringify({ decidedByUserId: `telegram:${actor}` }),
652
906
  });
653
907
  await answerCallbackQuery(ctx, token, query.id, "Approved");
@@ -673,9 +927,12 @@ async function handleCallbackQuery(ctx, token, query, baseUrl) {
673
927
  const approvalId = data.replace("reject_", "");
674
928
  ctx.logger.info("Rejection button clicked", { approvalId, actor });
675
929
  try {
676
- await ctx.http.fetch(`${baseUrl}/api/approvals/${approvalId}/reject`, {
930
+ await fetchPaperclipApi(ctx, `${baseUrl}/api/approvals/${approvalId}/reject`, {
677
931
  method: "POST",
678
- headers: { "Content-Type": "application/json" },
932
+ headers: {
933
+ "Content-Type": "application/json",
934
+ ...buildPaperclipAuthHeaders(boardApiToken),
935
+ },
679
936
  body: JSON.stringify({ decidedByUserId: `telegram:${actor}` }),
680
937
  });
681
938
  await answerCallbackQuery(ctx, token, query.id, "Rejected");