paperclip-plugin-telegram 0.1.0 → 0.2.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/README.md +19 -3
- package/package.json +3 -10
- package/src/acp-bridge.ts +1273 -0
- package/src/adapter.ts +129 -0
- package/src/command-registry.ts +482 -0
- package/src/commands.ts +346 -0
- package/src/constants.ts +51 -0
- package/src/escalation.ts +421 -0
- package/src/formatters.ts +148 -0
- package/src/index.ts +6 -0
- package/src/manifest.ts +246 -0
- package/src/media-pipeline.ts +234 -0
- package/src/telegram-api.ts +202 -0
- package/src/watch-registry.ts +369 -0
- package/src/worker.ts +783 -0
- package/tests/acp-bridge.test.ts +314 -0
- package/tests/command-registry.test.ts +283 -0
- package/tests/commands.test.ts +213 -0
- package/tests/escalation.test.ts +550 -0
- package/tests/formatters.test.ts +185 -0
- package/tests/media-pipeline.test.ts +324 -0
- package/tests/telegram-api.test.ts +108 -0
- package/tests/watch-registry.test.ts +404 -0
- package/tsconfig.json +16 -0
- package/dist/acp-bridge.d.ts +0 -12
- package/dist/acp-bridge.js +0 -166
- package/dist/acp-bridge.js.map +0 -1
- package/dist/commands.d.ts +0 -10
- package/dist/commands.js +0 -212
- package/dist/commands.js.map +0 -1
- package/dist/constants.d.ts +0 -24
- package/dist/constants.js +0 -25
- package/dist/constants.js.map +0 -1
- package/dist/formatters.d.ts +0 -13
- package/dist/formatters.js +0 -130
- package/dist/formatters.js.map +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +0 -1
- package/dist/manifest.d.ts +0 -3
- package/dist/manifest.js +0 -125
- package/dist/manifest.js.map +0 -1
- package/dist/telegram-api.d.ts +0 -28
- package/dist/telegram-api.js +0 -147
- package/dist/telegram-api.js.map +0 -1
- package/dist/worker.d.ts +0 -1
- package/dist/worker.js +0 -300
- package/dist/worker.js.map +0 -1
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { handleRegisterWatch, checkWatches } from "../src/watch-registry.js";
|
|
3
|
+
import type { PluginContext } from "@paperclipai/plugin-sdk";
|
|
4
|
+
|
|
5
|
+
let sentMessages: Array<{ chatId: string; text: string; options?: Record<string, unknown> }> = [];
|
|
6
|
+
let stateStore: Record<string, unknown> = {};
|
|
7
|
+
|
|
8
|
+
vi.mock("../src/telegram-api.js", async () => {
|
|
9
|
+
const actual = await vi.importActual("../src/telegram-api.js") as Record<string, unknown>;
|
|
10
|
+
return {
|
|
11
|
+
...actual,
|
|
12
|
+
sendMessage: vi.fn(async (_ctx: unknown, _token: string, chatId: string, text: string, options?: Record<string, unknown>) => {
|
|
13
|
+
sentMessages.push({ chatId, text, options });
|
|
14
|
+
return 1;
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
function mockCtx(overrides: Record<string, unknown> = {}): PluginContext {
|
|
20
|
+
return {
|
|
21
|
+
http: { fetch: vi.fn() },
|
|
22
|
+
metrics: { write: vi.fn() },
|
|
23
|
+
state: {
|
|
24
|
+
get: vi.fn(async (key: { stateKey: string }) => stateStore[key.stateKey] ?? null),
|
|
25
|
+
set: vi.fn(async (key: { stateKey: string }, value: unknown) => {
|
|
26
|
+
stateStore[key.stateKey] = value;
|
|
27
|
+
}),
|
|
28
|
+
},
|
|
29
|
+
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
|
|
30
|
+
companies: {
|
|
31
|
+
list: vi.fn().mockResolvedValue([{ id: "co-1" }]),
|
|
32
|
+
},
|
|
33
|
+
issues: {
|
|
34
|
+
list: vi.fn().mockResolvedValue([]),
|
|
35
|
+
},
|
|
36
|
+
agents: {
|
|
37
|
+
list: vi.fn().mockResolvedValue([]),
|
|
38
|
+
},
|
|
39
|
+
...overrides,
|
|
40
|
+
} as unknown as PluginContext;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
sentMessages = [];
|
|
45
|
+
stateStore = {};
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("handleRegisterWatch - storage and retrieval", () => {
|
|
49
|
+
it("registers a custom watch and stores it", async () => {
|
|
50
|
+
const ctx = mockCtx();
|
|
51
|
+
const result = await handleRegisterWatch(ctx, {
|
|
52
|
+
name: "Invoice Alert",
|
|
53
|
+
description: "Alert on overdue invoices",
|
|
54
|
+
entityType: "custom",
|
|
55
|
+
conditions: [{ field: "status", operator: "eq", value: "overdue" }],
|
|
56
|
+
template: "Invoice {{entityId}} is overdue",
|
|
57
|
+
chatId: "chat-1",
|
|
58
|
+
}, "co-1");
|
|
59
|
+
|
|
60
|
+
expect(result.content).toBeDefined();
|
|
61
|
+
const parsed = JSON.parse(result.content!);
|
|
62
|
+
expect(parsed.status).toBe("registered");
|
|
63
|
+
expect(parsed.watchId).toBeDefined();
|
|
64
|
+
expect(parsed.name).toBe("Invoice Alert");
|
|
65
|
+
|
|
66
|
+
// Check it was stored
|
|
67
|
+
const watches = stateStore["watches_co-1"] as Array<{ name: string }>;
|
|
68
|
+
expect(watches).toHaveLength(1);
|
|
69
|
+
expect(watches[0].name).toBe("Invoice Alert");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("registers a watch using built-in template", async () => {
|
|
73
|
+
const ctx = mockCtx();
|
|
74
|
+
const result = await handleRegisterWatch(ctx, {
|
|
75
|
+
builtinTemplate: "invoice-overdue",
|
|
76
|
+
chatId: "chat-1",
|
|
77
|
+
}, "co-1");
|
|
78
|
+
|
|
79
|
+
expect(result.content).toBeDefined();
|
|
80
|
+
const parsed = JSON.parse(result.content!);
|
|
81
|
+
expect(parsed.status).toBe("registered");
|
|
82
|
+
expect(parsed.name).toBe("Invoice Overdue");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("returns error when no name or builtinTemplate", async () => {
|
|
86
|
+
const ctx = mockCtx();
|
|
87
|
+
const result = await handleRegisterWatch(ctx, {
|
|
88
|
+
chatId: "chat-1",
|
|
89
|
+
}, "co-1");
|
|
90
|
+
|
|
91
|
+
expect(result.error).toContain("Either 'name' or 'builtinTemplate' is required");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("returns error when chatId is missing", async () => {
|
|
95
|
+
const ctx = mockCtx();
|
|
96
|
+
const result = await handleRegisterWatch(ctx, {
|
|
97
|
+
name: "test",
|
|
98
|
+
template: "test",
|
|
99
|
+
}, "co-1");
|
|
100
|
+
|
|
101
|
+
expect(result.error).toContain("chatId");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("returns error when custom watch has no template", async () => {
|
|
105
|
+
const ctx = mockCtx();
|
|
106
|
+
const result = await handleRegisterWatch(ctx, {
|
|
107
|
+
name: "test",
|
|
108
|
+
chatId: "chat-1",
|
|
109
|
+
}, "co-1");
|
|
110
|
+
|
|
111
|
+
expect(result.error).toContain("template");
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("appends to existing watch registry", async () => {
|
|
115
|
+
stateStore["watches_co-1"] = [{
|
|
116
|
+
watchId: "w1",
|
|
117
|
+
name: "Existing",
|
|
118
|
+
description: "",
|
|
119
|
+
entityType: "custom",
|
|
120
|
+
conditions: [],
|
|
121
|
+
template: "t",
|
|
122
|
+
chatId: "c",
|
|
123
|
+
companyId: "co-1",
|
|
124
|
+
createdBy: "test",
|
|
125
|
+
createdAt: "2026-01-01",
|
|
126
|
+
}];
|
|
127
|
+
const ctx = mockCtx();
|
|
128
|
+
await handleRegisterWatch(ctx, {
|
|
129
|
+
name: "New Watch",
|
|
130
|
+
template: "new template",
|
|
131
|
+
chatId: "chat-1",
|
|
132
|
+
}, "co-1");
|
|
133
|
+
|
|
134
|
+
const watches = stateStore["watches_co-1"] as unknown[];
|
|
135
|
+
expect(watches).toHaveLength(2);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe("checkWatches - rate limiting", () => {
|
|
140
|
+
it("suppresses when hourly count exceeds max", async () => {
|
|
141
|
+
const hourKey = `suggestion_hourly_co-1_${new Date().toISOString().slice(0, 13)}`;
|
|
142
|
+
stateStore[hourKey] = 11; // over limit of 10
|
|
143
|
+
|
|
144
|
+
stateStore["watches_co-1"] = [{
|
|
145
|
+
watchId: "w1",
|
|
146
|
+
name: "Test",
|
|
147
|
+
description: "",
|
|
148
|
+
entityType: "issue",
|
|
149
|
+
conditions: [],
|
|
150
|
+
template: "Alert: {{id}}",
|
|
151
|
+
chatId: "chat-1",
|
|
152
|
+
companyId: "co-1",
|
|
153
|
+
createdBy: "agent",
|
|
154
|
+
createdAt: "2026-01-01",
|
|
155
|
+
}];
|
|
156
|
+
|
|
157
|
+
const ctx = mockCtx({
|
|
158
|
+
issues: { list: vi.fn().mockResolvedValue([{ id: "i1", title: "Test", status: "open" }]) },
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
await checkWatches(ctx, "token", {
|
|
162
|
+
maxSuggestionsPerHourPerCompany: 10,
|
|
163
|
+
watchDeduplicationWindowMs: 86400000,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Rate limited, so no messages sent
|
|
167
|
+
expect(sentMessages.length).toBe(0);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("sends suggestion when under rate limit", async () => {
|
|
171
|
+
stateStore["watches_co-1"] = [{
|
|
172
|
+
watchId: "w1",
|
|
173
|
+
name: "Active Issues",
|
|
174
|
+
description: "",
|
|
175
|
+
entityType: "issue",
|
|
176
|
+
conditions: [{ field: "status", operator: "eq", value: "open" }],
|
|
177
|
+
template: "Issue {{id}} needs attention",
|
|
178
|
+
chatId: "chat-1",
|
|
179
|
+
companyId: "co-1",
|
|
180
|
+
createdBy: "agent",
|
|
181
|
+
createdAt: "2026-01-01",
|
|
182
|
+
}];
|
|
183
|
+
|
|
184
|
+
const ctx = mockCtx({
|
|
185
|
+
issues: { list: vi.fn().mockResolvedValue([{ id: "i1", title: "Test", status: "open" }]) },
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
await checkWatches(ctx, "token", {
|
|
189
|
+
maxSuggestionsPerHourPerCompany: 10,
|
|
190
|
+
watchDeduplicationWindowMs: 86400000,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
expect(sentMessages.length).toBe(1);
|
|
194
|
+
expect(sentMessages[0].text).toContain("needs attention");
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe("checkWatches - deduplication", () => {
|
|
199
|
+
it("suppresses same watch+entity within dedup window", async () => {
|
|
200
|
+
stateStore["watches_co-1"] = [{
|
|
201
|
+
watchId: "w1",
|
|
202
|
+
name: "Active Issues",
|
|
203
|
+
description: "",
|
|
204
|
+
entityType: "issue",
|
|
205
|
+
conditions: [{ field: "status", operator: "eq", value: "open" }],
|
|
206
|
+
template: "Issue {{id}} needs attention",
|
|
207
|
+
chatId: "chat-1",
|
|
208
|
+
companyId: "co-1",
|
|
209
|
+
createdBy: "agent",
|
|
210
|
+
createdAt: "2026-01-01",
|
|
211
|
+
}];
|
|
212
|
+
|
|
213
|
+
// Mark as already sent within the window
|
|
214
|
+
stateStore["suggestion_log_w1_i1"] = {
|
|
215
|
+
watchId: "w1",
|
|
216
|
+
entityId: "i1",
|
|
217
|
+
sentAt: new Date().toISOString(), // just now
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const ctx = mockCtx({
|
|
221
|
+
issues: { list: vi.fn().mockResolvedValue([{ id: "i1", title: "Test", status: "open" }]) },
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
await checkWatches(ctx, "token", {
|
|
225
|
+
maxSuggestionsPerHourPerCompany: 10,
|
|
226
|
+
watchDeduplicationWindowMs: 86400000, // 24h
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
expect(sentMessages.length).toBe(0);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("allows same watch+entity after dedup window expires", async () => {
|
|
233
|
+
stateStore["watches_co-1"] = [{
|
|
234
|
+
watchId: "w1",
|
|
235
|
+
name: "Active Issues",
|
|
236
|
+
description: "",
|
|
237
|
+
entityType: "issue",
|
|
238
|
+
conditions: [{ field: "status", operator: "eq", value: "open" }],
|
|
239
|
+
template: "Issue {{id}} needs attention",
|
|
240
|
+
chatId: "chat-1",
|
|
241
|
+
companyId: "co-1",
|
|
242
|
+
createdBy: "agent",
|
|
243
|
+
createdAt: "2026-01-01",
|
|
244
|
+
}];
|
|
245
|
+
|
|
246
|
+
// Sent 25 hours ago - outside 24h window
|
|
247
|
+
stateStore["suggestion_log_w1_i1"] = {
|
|
248
|
+
watchId: "w1",
|
|
249
|
+
entityId: "i1",
|
|
250
|
+
sentAt: new Date(Date.now() - 25 * 60 * 60 * 1000).toISOString(),
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const ctx = mockCtx({
|
|
254
|
+
issues: { list: vi.fn().mockResolvedValue([{ id: "i1", title: "Test", status: "open" }]) },
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
await checkWatches(ctx, "token", {
|
|
258
|
+
maxSuggestionsPerHourPerCompany: 10,
|
|
259
|
+
watchDeduplicationWindowMs: 86400000,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
expect(sentMessages.length).toBe(1);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
describe("Built-in template loading", () => {
|
|
267
|
+
it("loads invoice-overdue template with correct conditions", async () => {
|
|
268
|
+
const ctx = mockCtx();
|
|
269
|
+
const result = await handleRegisterWatch(ctx, {
|
|
270
|
+
builtinTemplate: "invoice-overdue",
|
|
271
|
+
chatId: "chat-1",
|
|
272
|
+
}, "co-1");
|
|
273
|
+
|
|
274
|
+
const watches = stateStore["watches_co-1"] as Array<{
|
|
275
|
+
name: string;
|
|
276
|
+
conditions: Array<{ field: string; operator: string }>;
|
|
277
|
+
}>;
|
|
278
|
+
expect(watches[0].name).toBe("Invoice Overdue");
|
|
279
|
+
expect(watches[0].conditions.length).toBe(2);
|
|
280
|
+
expect(watches[0].conditions[0].field).toBe("dueDate");
|
|
281
|
+
expect(watches[0].conditions[1].field).toBe("status");
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("loads lead-stale template with correct conditions", async () => {
|
|
285
|
+
const ctx = mockCtx();
|
|
286
|
+
const result = await handleRegisterWatch(ctx, {
|
|
287
|
+
builtinTemplate: "lead-stale",
|
|
288
|
+
chatId: "chat-1",
|
|
289
|
+
}, "co-1");
|
|
290
|
+
|
|
291
|
+
const watches = stateStore["watches_co-1"] as Array<{
|
|
292
|
+
name: string;
|
|
293
|
+
conditions: Array<{ field: string; operator: string }>;
|
|
294
|
+
}>;
|
|
295
|
+
expect(watches[0].name).toBe("Stale Lead");
|
|
296
|
+
expect(watches[0].conditions.length).toBe(2);
|
|
297
|
+
expect(watches[0].conditions[0].field).toBe("lastActivityAt");
|
|
298
|
+
expect(watches[0].conditions[1].field).toBe("status");
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it("returns error for unknown built-in template (falls through to custom)", async () => {
|
|
302
|
+
const ctx = mockCtx();
|
|
303
|
+
const result = await handleRegisterWatch(ctx, {
|
|
304
|
+
builtinTemplate: "nonexistent-template",
|
|
305
|
+
chatId: "chat-1",
|
|
306
|
+
}, "co-1");
|
|
307
|
+
|
|
308
|
+
// Will fail because no name and no valid builtin
|
|
309
|
+
expect(result.error).toContain("template");
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
describe("Watch condition matching", () => {
|
|
314
|
+
it("matches issues with eq condition", async () => {
|
|
315
|
+
stateStore["watches_co-1"] = [{
|
|
316
|
+
watchId: "w1",
|
|
317
|
+
name: "Open Issues",
|
|
318
|
+
description: "",
|
|
319
|
+
entityType: "issue",
|
|
320
|
+
conditions: [{ field: "status", operator: "eq", value: "open" }],
|
|
321
|
+
template: "Issue {{id}} is open",
|
|
322
|
+
chatId: "chat-1",
|
|
323
|
+
companyId: "co-1",
|
|
324
|
+
createdBy: "agent",
|
|
325
|
+
createdAt: "2026-01-01",
|
|
326
|
+
}];
|
|
327
|
+
|
|
328
|
+
const ctx = mockCtx({
|
|
329
|
+
issues: { list: vi.fn().mockResolvedValue([
|
|
330
|
+
{ id: "i1", status: "open" },
|
|
331
|
+
{ id: "i2", status: "closed" },
|
|
332
|
+
]) },
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
await checkWatches(ctx, "token", {
|
|
336
|
+
maxSuggestionsPerHourPerCompany: 10,
|
|
337
|
+
watchDeduplicationWindowMs: 86400000,
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// Only i1 should match
|
|
341
|
+
expect(sentMessages.length).toBe(1);
|
|
342
|
+
expect(sentMessages[0].text).toContain("i1");
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it("matches issues with ne condition", async () => {
|
|
346
|
+
stateStore["watches_co-1"] = [{
|
|
347
|
+
watchId: "w1",
|
|
348
|
+
name: "Non-closed Issues",
|
|
349
|
+
description: "",
|
|
350
|
+
entityType: "issue",
|
|
351
|
+
conditions: [{ field: "status", operator: "ne", value: "closed" }],
|
|
352
|
+
template: "Issue {{id}} is not closed",
|
|
353
|
+
chatId: "chat-1",
|
|
354
|
+
companyId: "co-1",
|
|
355
|
+
createdBy: "agent",
|
|
356
|
+
createdAt: "2026-01-01",
|
|
357
|
+
}];
|
|
358
|
+
|
|
359
|
+
const ctx = mockCtx({
|
|
360
|
+
issues: { list: vi.fn().mockResolvedValue([
|
|
361
|
+
{ id: "i1", status: "open" },
|
|
362
|
+
{ id: "i2", status: "closed" },
|
|
363
|
+
]) },
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
await checkWatches(ctx, "token", {
|
|
367
|
+
maxSuggestionsPerHourPerCompany: 10,
|
|
368
|
+
watchDeduplicationWindowMs: 86400000,
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
expect(sentMessages.length).toBe(1);
|
|
372
|
+
expect(sentMessages[0].text).toContain("i1");
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it("matches issues with contains condition", async () => {
|
|
376
|
+
stateStore["watches_co-1"] = [{
|
|
377
|
+
watchId: "w1",
|
|
378
|
+
name: "Bug Issues",
|
|
379
|
+
description: "",
|
|
380
|
+
entityType: "issue",
|
|
381
|
+
conditions: [{ field: "title", operator: "contains", value: "bug" }],
|
|
382
|
+
template: "Bug: {{id}}",
|
|
383
|
+
chatId: "chat-1",
|
|
384
|
+
companyId: "co-1",
|
|
385
|
+
createdBy: "agent",
|
|
386
|
+
createdAt: "2026-01-01",
|
|
387
|
+
}];
|
|
388
|
+
|
|
389
|
+
const ctx = mockCtx({
|
|
390
|
+
issues: { list: vi.fn().mockResolvedValue([
|
|
391
|
+
{ id: "i1", title: "Fix bug in login" },
|
|
392
|
+
{ id: "i2", title: "Add feature" },
|
|
393
|
+
]) },
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
await checkWatches(ctx, "token", {
|
|
397
|
+
maxSuggestionsPerHourPerCompany: 10,
|
|
398
|
+
watchDeduplicationWindowMs: 86400000,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
expect(sentMessages.length).toBe(1);
|
|
402
|
+
expect(sentMessages[0].text).toContain("i1");
|
|
403
|
+
});
|
|
404
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "Node16",
|
|
5
|
+
"moduleResolution": "Node16",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"sourceMap": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*.ts"],
|
|
15
|
+
"exclude": ["node_modules", "dist"]
|
|
16
|
+
}
|
package/dist/acp-bridge.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { PluginContext } from "@paperclipai/plugin-sdk";
|
|
2
|
-
type AcpOutputEvent = {
|
|
3
|
-
sessionId: string;
|
|
4
|
-
chatId: string;
|
|
5
|
-
threadId: number;
|
|
6
|
-
text: string;
|
|
7
|
-
done?: boolean;
|
|
8
|
-
};
|
|
9
|
-
export declare function handleAcpCommand(ctx: PluginContext, token: string, chatId: string, args: string, messageThreadId?: number): Promise<void>;
|
|
10
|
-
export declare function routeMessageToAcp(ctx: PluginContext, chatId: string, threadId: number, text: string): Promise<boolean>;
|
|
11
|
-
export declare function handleAcpOutput(ctx: PluginContext, token: string, event: AcpOutputEvent): Promise<void>;
|
|
12
|
-
export {};
|
package/dist/acp-bridge.js
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { sendMessage, escapeMarkdownV2, sendChatAction } from "./telegram-api.js";
|
|
2
|
-
export async function handleAcpCommand(ctx, token, chatId, args, messageThreadId) {
|
|
3
|
-
const parts = args.trim().split(/\s+/);
|
|
4
|
-
const subcommand = parts[0]?.toLowerCase() ?? "";
|
|
5
|
-
switch (subcommand) {
|
|
6
|
-
case "spawn":
|
|
7
|
-
await handleAcpSpawn(ctx, token, chatId, parts.slice(1).join(" "), messageThreadId);
|
|
8
|
-
break;
|
|
9
|
-
case "status":
|
|
10
|
-
await handleAcpStatus(ctx, token, chatId, messageThreadId);
|
|
11
|
-
break;
|
|
12
|
-
case "cancel":
|
|
13
|
-
await handleAcpCancel(ctx, token, chatId, messageThreadId);
|
|
14
|
-
break;
|
|
15
|
-
case "close":
|
|
16
|
-
await handleAcpClose(ctx, token, chatId, messageThreadId);
|
|
17
|
-
break;
|
|
18
|
-
default:
|
|
19
|
-
await sendMessage(ctx, token, chatId, [
|
|
20
|
-
escapeMarkdownV2("🔌") + " *ACP Commands*",
|
|
21
|
-
"",
|
|
22
|
-
`/acp spawn <agent\\-name> \\- ${escapeMarkdownV2("Start a coding agent session in this thread")}`,
|
|
23
|
-
`/acp status \\- ${escapeMarkdownV2("Show current ACP session status")}`,
|
|
24
|
-
`/acp cancel \\- ${escapeMarkdownV2("Cancel the running agent task")}`,
|
|
25
|
-
`/acp close \\- ${escapeMarkdownV2("End the ACP session and unbind this thread")}`,
|
|
26
|
-
].join("\n"), { parseMode: "MarkdownV2", messageThreadId });
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
async function handleAcpSpawn(ctx, token, chatId, agentName, messageThreadId) {
|
|
30
|
-
if (!agentName.trim()) {
|
|
31
|
-
await sendMessage(ctx, token, chatId, "Usage: /acp spawn <agent-name>", {
|
|
32
|
-
messageThreadId,
|
|
33
|
-
});
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
if (!messageThreadId) {
|
|
37
|
-
await sendMessage(ctx, token, chatId, "ACP sessions must be started inside a topic thread.", { messageThreadId });
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
const existingBinding = await getAcpBinding(ctx, chatId, messageThreadId);
|
|
41
|
-
if (existingBinding) {
|
|
42
|
-
await sendMessage(ctx, token, chatId, `This thread already has an ACP session: \`${escapeMarkdownV2(existingBinding.sessionId)}\``, { parseMode: "MarkdownV2", messageThreadId });
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
await sendChatAction(ctx, token, chatId);
|
|
46
|
-
const sessionId = `acp_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
47
|
-
await ctx.state.set({ scopeKind: "instance", stateKey: `acp_${chatId}_${messageThreadId}` }, { sessionId, agentName: agentName.trim(), boundAt: new Date().toISOString() });
|
|
48
|
-
await ctx.events.emit("acp-message", "", {
|
|
49
|
-
type: "spawn",
|
|
50
|
-
sessionId,
|
|
51
|
-
agentName: agentName.trim(),
|
|
52
|
-
chatId,
|
|
53
|
-
threadId: messageThreadId,
|
|
54
|
-
});
|
|
55
|
-
await sendMessage(ctx, token, chatId, [
|
|
56
|
-
escapeMarkdownV2("🔌") + " *ACP Session Started*",
|
|
57
|
-
"",
|
|
58
|
-
`Agent: *${escapeMarkdownV2(agentName.trim())}*`,
|
|
59
|
-
`Session: \`${escapeMarkdownV2(sessionId)}\``,
|
|
60
|
-
"",
|
|
61
|
-
escapeMarkdownV2("Send messages in this thread to interact with the agent."),
|
|
62
|
-
].join("\n"), { parseMode: "MarkdownV2", messageThreadId });
|
|
63
|
-
ctx.logger.info("ACP session spawned", { sessionId, agentName: agentName.trim(), chatId, threadId: messageThreadId });
|
|
64
|
-
}
|
|
65
|
-
async function handleAcpStatus(ctx, token, chatId, messageThreadId) {
|
|
66
|
-
if (!messageThreadId) {
|
|
67
|
-
await sendMessage(ctx, token, chatId, "Run /acp status inside a thread with an active session.", {
|
|
68
|
-
messageThreadId,
|
|
69
|
-
});
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
const binding = await getAcpBinding(ctx, chatId, messageThreadId);
|
|
73
|
-
if (!binding) {
|
|
74
|
-
await sendMessage(ctx, token, chatId, "No ACP session bound to this thread.", {
|
|
75
|
-
messageThreadId,
|
|
76
|
-
});
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
await sendMessage(ctx, token, chatId, [
|
|
80
|
-
escapeMarkdownV2("🔌") + " *ACP Session*",
|
|
81
|
-
"",
|
|
82
|
-
`Agent: *${escapeMarkdownV2(binding.agentName)}*`,
|
|
83
|
-
`Session: \`${escapeMarkdownV2(binding.sessionId)}\``,
|
|
84
|
-
`Started: ${escapeMarkdownV2(binding.boundAt)}`,
|
|
85
|
-
].join("\n"), { parseMode: "MarkdownV2", messageThreadId });
|
|
86
|
-
}
|
|
87
|
-
async function handleAcpCancel(ctx, token, chatId, messageThreadId) {
|
|
88
|
-
if (!messageThreadId) {
|
|
89
|
-
await sendMessage(ctx, token, chatId, "Run /acp cancel inside a thread with an active session.", {
|
|
90
|
-
messageThreadId,
|
|
91
|
-
});
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
const binding = await getAcpBinding(ctx, chatId, messageThreadId);
|
|
95
|
-
if (!binding) {
|
|
96
|
-
await sendMessage(ctx, token, chatId, "No ACP session bound to this thread.", {
|
|
97
|
-
messageThreadId,
|
|
98
|
-
});
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
await ctx.events.emit("acp-message", "", {
|
|
102
|
-
type: "cancel",
|
|
103
|
-
sessionId: binding.sessionId,
|
|
104
|
-
chatId,
|
|
105
|
-
threadId: messageThreadId,
|
|
106
|
-
});
|
|
107
|
-
await sendMessage(ctx, token, chatId, `${escapeMarkdownV2("⏹")} Cancellation requested for session \`${escapeMarkdownV2(binding.sessionId)}\``, { parseMode: "MarkdownV2", messageThreadId });
|
|
108
|
-
ctx.logger.info("ACP cancel requested", { sessionId: binding.sessionId, chatId, threadId: messageThreadId });
|
|
109
|
-
}
|
|
110
|
-
async function handleAcpClose(ctx, token, chatId, messageThreadId) {
|
|
111
|
-
if (!messageThreadId) {
|
|
112
|
-
await sendMessage(ctx, token, chatId, "Run /acp close inside a thread with an active session.", {
|
|
113
|
-
messageThreadId,
|
|
114
|
-
});
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
const binding = await getAcpBinding(ctx, chatId, messageThreadId);
|
|
118
|
-
if (!binding) {
|
|
119
|
-
await sendMessage(ctx, token, chatId, "No ACP session bound to this thread.", {
|
|
120
|
-
messageThreadId,
|
|
121
|
-
});
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
await ctx.events.emit("acp-message", "", {
|
|
125
|
-
type: "close",
|
|
126
|
-
sessionId: binding.sessionId,
|
|
127
|
-
chatId,
|
|
128
|
-
threadId: messageThreadId,
|
|
129
|
-
});
|
|
130
|
-
await ctx.state.set({ scopeKind: "instance", stateKey: `acp_${chatId}_${messageThreadId}` }, null);
|
|
131
|
-
await sendMessage(ctx, token, chatId, `${escapeMarkdownV2("🔌")} ACP session \`${escapeMarkdownV2(binding.sessionId)}\` closed\\.`, { parseMode: "MarkdownV2", messageThreadId });
|
|
132
|
-
ctx.logger.info("ACP session closed", { sessionId: binding.sessionId, chatId, threadId: messageThreadId });
|
|
133
|
-
}
|
|
134
|
-
export async function routeMessageToAcp(ctx, chatId, threadId, text) {
|
|
135
|
-
const binding = await getAcpBinding(ctx, chatId, threadId);
|
|
136
|
-
if (!binding)
|
|
137
|
-
return false;
|
|
138
|
-
await ctx.events.emit("acp-message", "", {
|
|
139
|
-
type: "message",
|
|
140
|
-
sessionId: binding.sessionId,
|
|
141
|
-
chatId,
|
|
142
|
-
threadId,
|
|
143
|
-
text,
|
|
144
|
-
});
|
|
145
|
-
ctx.logger.info("Routed message to ACP session", { sessionId: binding.sessionId, chatId, threadId });
|
|
146
|
-
return true;
|
|
147
|
-
}
|
|
148
|
-
export async function handleAcpOutput(ctx, token, event) {
|
|
149
|
-
const { chatId, threadId, text, done } = event;
|
|
150
|
-
const prefix = done
|
|
151
|
-
? escapeMarkdownV2("✅")
|
|
152
|
-
: escapeMarkdownV2("🤖");
|
|
153
|
-
const formatted = `${prefix} ${escapeMarkdownV2(text)}`;
|
|
154
|
-
await sendMessage(ctx, token, chatId, formatted, {
|
|
155
|
-
parseMode: "MarkdownV2",
|
|
156
|
-
messageThreadId: threadId,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
async function getAcpBinding(ctx, chatId, threadId) {
|
|
160
|
-
const binding = await ctx.state.get({
|
|
161
|
-
scopeKind: "instance",
|
|
162
|
-
stateKey: `acp_${chatId}_${threadId}`,
|
|
163
|
-
});
|
|
164
|
-
return binding;
|
|
165
|
-
}
|
|
166
|
-
//# sourceMappingURL=acp-bridge.js.map
|
package/dist/acp-bridge.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"acp-bridge.js","sourceRoot":"","sources":["../src/acp-bridge.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAgBlF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAkB,EAClB,KAAa,EACb,MAAc,EACd,IAAY,EACZ,eAAwB;IAExB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAEjD,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,OAAO;YACV,MAAM,cAAc,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,eAAe,CAAC,CAAC;YACpF,MAAM;QACR,KAAK,QAAQ;YACX,MAAM,eAAe,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;YAC3D,MAAM;QACR,KAAK,QAAQ;YACX,MAAM,eAAe,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;YAC3D,MAAM;QACR,KAAK,OAAO;YACV,MAAM,cAAc,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;YAC1D,MAAM;QACR;YACE,MAAM,WAAW,CACf,GAAG,EACH,KAAK,EACL,MAAM,EACN;gBACE,gBAAgB,CAAC,IAAI,CAAC,GAAG,iBAAiB;gBAC1C,EAAE;gBACF,iCAAiC,gBAAgB,CAAC,6CAA6C,CAAC,EAAE;gBAClG,mBAAmB,gBAAgB,CAAC,iCAAiC,CAAC,EAAE;gBACxE,mBAAmB,gBAAgB,CAAC,+BAA+B,CAAC,EAAE;gBACtE,kBAAkB,gBAAgB,CAAC,4CAA4C,CAAC,EAAE;aACnF,CAAC,IAAI,CAAC,IAAI,CAAC,EACZ,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,CAC7C,CAAC;IACN,CAAC;AACH,CAAC;AAED,KAAK,UAAU,cAAc,CAC3B,GAAkB,EAClB,KAAa,EACb,MAAc,EACd,SAAiB,EACjB,eAAwB;IAExB,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;QACtB,MAAM,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,gCAAgC,EAAE;YACtE,eAAe;SAChB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,WAAW,CACf,GAAG,EACH,KAAK,EACL,MAAM,EACN,qDAAqD,EACrD,EAAE,eAAe,EAAE,CACpB,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,eAAe,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;IAC1E,IAAI,eAAe,EAAE,CAAC;QACpB,MAAM,WAAW,CACf,GAAG,EACH,KAAK,EACL,MAAM,EACN,6CAA6C,gBAAgB,CAAC,eAAe,CAAC,SAAS,CAAC,IAAI,EAC5F,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,CAC7C,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,cAAc,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAEzC,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAEhF,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CACjB,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,MAAM,IAAI,eAAe,EAAE,EAAE,EACvE,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAuB,CACnG,CAAC;IAEF,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,EAAE;QACvC,IAAI,EAAE,OAAO;QACb,SAAS;QACT,SAAS,EAAE,SAAS,CAAC,IAAI,EAAE;QAC3B,MAAM;QACN,QAAQ,EAAE,eAAe;KAC1B,CAAC,CAAC;IAEH,MAAM,WAAW,CACf,GAAG,EACH,KAAK,EACL,MAAM,EACN;QACE,gBAAgB,CAAC,IAAI,CAAC,GAAG,wBAAwB;QACjD,EAAE;QACF,WAAW,gBAAgB,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,GAAG;QAChD,cAAc,gBAAgB,CAAC,SAAS,CAAC,IAAI;QAC7C,EAAE;QACF,gBAAgB,CAAC,0DAA0D,CAAC;KAC7E,CAAC,IAAI,CAAC,IAAI,CAAC,EACZ,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,CAC7C,CAAC;IAEF,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC,CAAC;AACxH,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,GAAkB,EAClB,KAAa,EACb,MAAc,EACd,eAAwB;IAExB,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,yDAAyD,EAAE;YAC/F,eAAe;SAChB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;IAClE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,sCAAsC,EAAE;YAC5E,eAAe;SAChB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,WAAW,CACf,GAAG,EACH,KAAK,EACL,MAAM,EACN;QACE,gBAAgB,CAAC,IAAI,CAAC,GAAG,gBAAgB;QACzC,EAAE;QACF,WAAW,gBAAgB,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG;QACjD,cAAc,gBAAgB,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI;QACrD,YAAY,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;KAChD,CAAC,IAAI,CAAC,IAAI,CAAC,EACZ,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,CAC7C,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,GAAkB,EAClB,KAAa,EACb,MAAc,EACd,eAAwB;IAExB,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,yDAAyD,EAAE;YAC/F,eAAe;SAChB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;IAClE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,sCAAsC,EAAE;YAC5E,eAAe;SAChB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,EAAE;QACvC,IAAI,EAAE,QAAQ;QACd,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM;QACN,QAAQ,EAAE,eAAe;KAC1B,CAAC,CAAC;IAEH,MAAM,WAAW,CACf,GAAG,EACH,KAAK,EACL,MAAM,EACN,GAAG,gBAAgB,CAAC,GAAG,CAAC,yCAAyC,gBAAgB,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EACxG,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,CAC7C,CAAC;IAEF,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC,CAAC;AAC/G,CAAC;AAED,KAAK,UAAU,cAAc,CAC3B,GAAkB,EAClB,KAAa,EACb,MAAc,EACd,eAAwB;IAExB,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,wDAAwD,EAAE;YAC9F,eAAe;SAChB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;IAClE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,sCAAsC,EAAE;YAC5E,eAAe;SAChB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,EAAE;QACvC,IAAI,EAAE,OAAO;QACb,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM;QACN,QAAQ,EAAE,eAAe;KAC1B,CAAC,CAAC;IAEH,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CACjB,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,MAAM,IAAI,eAAe,EAAE,EAAE,EACvE,IAAI,CACL,CAAC;IAEF,MAAM,WAAW,CACf,GAAG,EACH,KAAK,EACL,MAAM,EACN,GAAG,gBAAgB,CAAC,IAAI,CAAC,kBAAkB,gBAAgB,CAAC,OAAO,CAAC,SAAS,CAAC,cAAc,EAC5F,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,CAC7C,CAAC;IAEF,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC,CAAC;AAC7G,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAkB,EAClB,MAAc,EACd,QAAgB,EAChB,IAAY;IAEZ,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC3D,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAE3B,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,EAAE;QACvC,IAAI,EAAE,SAAS;QACf,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM;QACN,QAAQ;QACR,IAAI;KACL,CAAC,CAAC;IAEH,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,+BAA+B,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACrG,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAkB,EAClB,KAAa,EACb,KAAqB;IAErB,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAE/C,MAAM,MAAM,GAAG,IAAI;QACjB,CAAC,CAAC,gBAAgB,CAAC,GAAG,CAAC;QACvB,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAE3B,MAAM,SAAS,GAAG,GAAG,MAAM,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;IAExD,MAAM,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE;QAC/C,SAAS,EAAE,YAAY;QACvB,eAAe,EAAE,QAAQ;KAC1B,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,GAAkB,EAClB,MAAc,EACd,QAAgB;IAEhB,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;QAClC,SAAS,EAAE,UAAU;QACrB,QAAQ,EAAE,OAAO,MAAM,IAAI,QAAQ,EAAE;KACtC,CAAsB,CAAC;IACxB,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/commands.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { PluginContext } from "@paperclipai/plugin-sdk";
|
|
2
|
-
type BotCommand = {
|
|
3
|
-
command: string;
|
|
4
|
-
description: string;
|
|
5
|
-
};
|
|
6
|
-
export declare const BOT_COMMANDS: BotCommand[];
|
|
7
|
-
export declare function handleCommand(ctx: PluginContext, token: string, chatId: string, command: string, args: string, messageThreadId?: number, baseUrl?: string): Promise<void>;
|
|
8
|
-
export declare function handleConnectTopic(ctx: PluginContext, token: string, chatId: string, args: string, messageThreadId?: number): Promise<void>;
|
|
9
|
-
export declare function getTopicForProject(ctx: PluginContext, chatId: string, projectName?: string): Promise<number | undefined>;
|
|
10
|
-
export {};
|