@coffer-org/plugin-telegram 2.2.2 → 2.3.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/dist/runtime/bot.js +73 -8
- package/dist/runtime/chain-store.js +21 -2
- package/dist/runtime/config.d.ts +5 -0
- package/dist/runtime/config.js +9 -0
- package/dist/runtime/model-command.d.ts +12 -0
- package/dist/runtime/model-command.js +32 -0
- package/dist/schema.js +76 -12
- package/package.json +4 -4
package/dist/runtime/bot.js
CHANGED
|
@@ -3,10 +3,13 @@ import path from 'node:path';
|
|
|
3
3
|
import { TelegramClient, Api } from 'teleproto';
|
|
4
4
|
import { LogLevel } from 'teleproto/extensions/Logger.js';
|
|
5
5
|
import { StringSession } from 'teleproto/sessions/index.js';
|
|
6
|
-
import { NewMessage } from 'teleproto/events/index.js';
|
|
7
|
-
import {
|
|
6
|
+
import { NewMessage, CallbackQuery } from 'teleproto/events/index.js';
|
|
7
|
+
import { Button } from 'teleproto/tl/custom/button.js';
|
|
8
|
+
import { handleIncoming, loadGatePolicy, makeLiveChannel, chunk, listAgentCatalog, isSenderAllowed, liveAgentId, } from '@coffer-org/plugin-orchestrator/runtime';
|
|
9
|
+
import { getThreadState, setThreadState } from '@coffer-org/server/thread-state';
|
|
8
10
|
import { recordUser, recordAssistant, buildChain } from "./chain-store.js";
|
|
9
|
-
import { loadBotConfig, hasCredentials, loadReasoningDisplay } from "./config.js";
|
|
11
|
+
import { loadBotConfig, hasCredentials, loadReasoningDisplay, loadModelStrings } from "./config.js";
|
|
12
|
+
import { buildModelKeyboard, isModelCommand, parseModelCallback } from "./model-command.js";
|
|
10
13
|
import { getLogger } from '@coffer-org/sdk/logger';
|
|
11
14
|
const log = getLogger('telegram');
|
|
12
15
|
const FALLBACK_REPLY_WINDOW_MS = 1_800_000;
|
|
@@ -55,7 +58,7 @@ export function renderWithReasoning(mode, max) {
|
|
|
55
58
|
};
|
|
56
59
|
}
|
|
57
60
|
const TELEGRAM_FORMAT = [
|
|
58
|
-
|
|
61
|
+
"CRITICAL OUTPUT FORMAT — Telegram HTML ONLY. Format the reply strictly with Telegram's HTML subset (<b>, <i>, <code>, <a>, …) and NOTHING else. NEVER use Markdown — no *bold*, _italic_, **bold**, `code`, ```blocks```, # headings, - bullets, or | tables. Markdown does not render here; it shows up as literal characters and breaks the message. When in doubt, use an HTML tag or plain text.",
|
|
59
62
|
'Inline styling (tags may nest): <b>bold</b>, <i>italic</i>, <u>underline</u>, <s>strike</s>, <code>inline code</code>, <spoiler>spoiler</spoiler>. Links: <a href="https://…">text</a> (also <a href="tg://user?id=123">mention</a>).',
|
|
60
63
|
'Blocks: <pre>code block</pre> or, for syntax highlight, <pre><code class="language-python">…</code></pre>. Quotes: <blockquote>quote</blockquote>, or <blockquote expandable>long collapsible quote</blockquote>. Bullet lists: start plain lines with "• ".',
|
|
61
64
|
'Only those tags are parsed. NOT supported here (do not use): <tg-spoiler>, <span>, <ins>, <strike>, <tg-time> — use <spoiler>, <u>, <s> instead. Avoid <tg-emoji> (needs a custom-emoji id + Premium); use ordinary emoji.',
|
|
@@ -74,7 +77,13 @@ export function makeReplyFactory(t, display) {
|
|
|
74
77
|
maxLength: TG_MAX,
|
|
75
78
|
render: renderWithReasoning(display, TG_MAX),
|
|
76
79
|
});
|
|
77
|
-
return display === 'separate'
|
|
80
|
+
return display === 'separate'
|
|
81
|
+
? ch
|
|
82
|
+
: {
|
|
83
|
+
...ch,
|
|
84
|
+
segment() {
|
|
85
|
+
},
|
|
86
|
+
};
|
|
78
87
|
};
|
|
79
88
|
}
|
|
80
89
|
function mediaInfo(message) {
|
|
@@ -159,6 +168,28 @@ export async function startBot(opts = {}) {
|
|
|
159
168
|
}
|
|
160
169
|
}
|
|
161
170
|
}
|
|
171
|
+
async function sendModelKeyboard(peer, rows, prompt) {
|
|
172
|
+
if (rows.length === 0) {
|
|
173
|
+
log.warn('/model: no agent presets registered — nothing to show');
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
await tg.sendMessage(peer, {
|
|
178
|
+
message: prompt,
|
|
179
|
+
buttons: rows.map((row) => row.map((b) => Button.inline(b.text, Buffer.from(b.data, 'utf-8')))),
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
log.warn(`send /model keyboard: ${err instanceof Error ? err.message : String(err)}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async function answerCallback(query, text) {
|
|
187
|
+
try {
|
|
188
|
+
await query.answer({ message: text });
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
}
|
|
192
|
+
}
|
|
162
193
|
function startTypingPeer(peer) {
|
|
163
194
|
let logged = false;
|
|
164
195
|
let stopped = false;
|
|
@@ -180,9 +211,7 @@ export async function startBot(opts = {}) {
|
|
|
180
211
|
}
|
|
181
212
|
if (stopped)
|
|
182
213
|
return;
|
|
183
|
-
const ping = () => tg
|
|
184
|
-
.invoke(new Api.messages.SetTyping({ peer: input, action: new Api.SendMessageTypingAction() }))
|
|
185
|
-
.catch(warn);
|
|
214
|
+
const ping = () => tg.invoke(new Api.messages.SetTyping({ peer: input, action: new Api.SendMessageTypingAction() })).catch(warn);
|
|
186
215
|
void ping();
|
|
187
216
|
timer = setInterval(() => void ping(), 5000);
|
|
188
217
|
})();
|
|
@@ -219,6 +248,14 @@ export async function startBot(opts = {}) {
|
|
|
219
248
|
try {
|
|
220
249
|
const chatId = String(event.chatId ?? '?');
|
|
221
250
|
const userId = message.senderId?.toString() ?? '?';
|
|
251
|
+
if (isModelCommand(text)) {
|
|
252
|
+
if (!(await isSenderAllowed('telegram', userId)))
|
|
253
|
+
return;
|
|
254
|
+
const strings = await loadModelStrings();
|
|
255
|
+
const rows = buildModelKeyboard(await listAgentCatalog(), await getThreadState('telegram', chatId));
|
|
256
|
+
await sendModelKeyboard(peer, rows, strings.prompt);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
222
259
|
const incomingMsgId = String(message.id);
|
|
223
260
|
const replyTo = message.replyTo?.replyToMsgId ?? null;
|
|
224
261
|
let replyToId = replyTo != null ? String(replyTo) : null;
|
|
@@ -275,6 +312,8 @@ export async function startBot(opts = {}) {
|
|
|
275
312
|
}
|
|
276
313
|
: undefined;
|
|
277
314
|
const reasoningDisplay = await loadReasoningDisplay();
|
|
315
|
+
const selection = await getThreadState('telegram', chatId);
|
|
316
|
+
const selectedAgentId = liveAgentId(selection.agentId);
|
|
278
317
|
const connector = {
|
|
279
318
|
id: 'telegram',
|
|
280
319
|
reply: makeReplyFactory({
|
|
@@ -299,6 +338,8 @@ export async function startBot(opts = {}) {
|
|
|
299
338
|
sender: { id: userId, displayName },
|
|
300
339
|
messages,
|
|
301
340
|
...(prepareAttachments ? { prepareAttachments } : {}),
|
|
341
|
+
...(selectedAgentId ? { agentId: selectedAgentId } : {}),
|
|
342
|
+
...(selection.presetId ? { presetId: selection.presetId } : {}),
|
|
302
343
|
});
|
|
303
344
|
}
|
|
304
345
|
finally {
|
|
@@ -309,6 +350,30 @@ export async function startBot(opts = {}) {
|
|
|
309
350
|
log.error(`message handling: ${err instanceof Error ? err.message : String(err)}`);
|
|
310
351
|
}
|
|
311
352
|
}, new NewMessage({}));
|
|
353
|
+
tg.addEventHandler(async (event) => {
|
|
354
|
+
try {
|
|
355
|
+
const data = event.data?.toString('utf-8');
|
|
356
|
+
if (!data)
|
|
357
|
+
return;
|
|
358
|
+
const picked = parseModelCallback(data);
|
|
359
|
+
if (!picked)
|
|
360
|
+
return;
|
|
361
|
+
const senderId = event.senderId?.toString() ?? '?';
|
|
362
|
+
if (!(await isSenderAllowed('telegram', senderId)))
|
|
363
|
+
return;
|
|
364
|
+
if (!liveAgentId(picked.agentId)) {
|
|
365
|
+
log.warn(`/model tap named an unregistered agent: ${picked.agentId}`);
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const chatId = String(event.chatId ?? '?');
|
|
369
|
+
await setThreadState('telegram', chatId, picked);
|
|
370
|
+
const strings = await loadModelStrings();
|
|
371
|
+
await answerCallback(event, strings.confirm);
|
|
372
|
+
}
|
|
373
|
+
catch (err) {
|
|
374
|
+
log.error(`callback query handling: ${err instanceof Error ? err.message : String(err)}`);
|
|
375
|
+
}
|
|
376
|
+
}, new CallbackQuery({}));
|
|
312
377
|
clearInterval(healthTimer);
|
|
313
378
|
healthTimer = setInterval(() => {
|
|
314
379
|
if (!tg.connected) {
|
|
@@ -4,7 +4,17 @@ const log = getLogger('telegram');
|
|
|
4
4
|
const CONNECTOR = 'telegram';
|
|
5
5
|
const DEFAULT_MAX_DEPTH = 30;
|
|
6
6
|
export async function recordUser(m) {
|
|
7
|
-
await putThreadMessage({
|
|
7
|
+
await putThreadMessage({
|
|
8
|
+
connector: CONNECTOR,
|
|
9
|
+
chatId: m.chatId,
|
|
10
|
+
msgId: m.msgId,
|
|
11
|
+
role: 'user',
|
|
12
|
+
sender: m.sender ?? null,
|
|
13
|
+
attachments: m.attachments,
|
|
14
|
+
text: m.text,
|
|
15
|
+
ts: m.ts,
|
|
16
|
+
replyToId: m.replyToId,
|
|
17
|
+
});
|
|
8
18
|
}
|
|
9
19
|
export async function recordAssistant(m) {
|
|
10
20
|
if (m.botMsgId == null)
|
|
@@ -32,7 +42,16 @@ export async function buildChain(headMsgId, opts) {
|
|
|
32
42
|
if (!fetched)
|
|
33
43
|
break;
|
|
34
44
|
const role = fetched.senderId === opts.botId ? 'assistant' : 'user';
|
|
35
|
-
await putThreadMessage({
|
|
45
|
+
await putThreadMessage({
|
|
46
|
+
connector: CONNECTOR,
|
|
47
|
+
chatId: opts.chatId,
|
|
48
|
+
msgId: cur,
|
|
49
|
+
role,
|
|
50
|
+
sender: null,
|
|
51
|
+
text: fetched.text,
|
|
52
|
+
ts: fetched.date,
|
|
53
|
+
replyToId: fetched.replyToId,
|
|
54
|
+
});
|
|
36
55
|
stored = { msgId: cur, role, sender: null, text: fetched.text, ts: fetched.date, replyToId: fetched.replyToId };
|
|
37
56
|
}
|
|
38
57
|
if (stored.role !== 'reasoning') {
|
package/dist/runtime/config.d.ts
CHANGED
|
@@ -15,3 +15,8 @@ export declare function hasCredentials(cfg: Pick<BotConfig, 'apiId' | 'apiHash'
|
|
|
15
15
|
export type ReasoningDisplay = 'off' | 'collapsible' | 'separate';
|
|
16
16
|
export declare function toReasoningDisplay(v: unknown): ReasoningDisplay;
|
|
17
17
|
export declare function loadReasoningDisplay(): Promise<ReasoningDisplay>;
|
|
18
|
+
export interface ModelStrings {
|
|
19
|
+
prompt: string;
|
|
20
|
+
confirm: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function loadModelStrings(): Promise<ModelStrings>;
|
package/dist/runtime/config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
3
|
import { getPluginSettings } from '@coffer-org/server/plugin-runtime';
|
|
4
|
+
import { loadPluginI18n } from '@coffer-org/server/plugin-i18n';
|
|
4
5
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
5
6
|
export const PLUGIN_ROOT = path.resolve(__dirname, '../..');
|
|
6
7
|
export function loadBotConfig(opts = {}) {
|
|
@@ -23,3 +24,11 @@ export function toReasoningDisplay(v) {
|
|
|
23
24
|
export async function loadReasoningDisplay() {
|
|
24
25
|
return toReasoningDisplay((await getPluginSettings('telegram'))['reasoning_display']);
|
|
25
26
|
}
|
|
27
|
+
const MODEL_STRINGS_FALLBACK = { prompt: 'Choose a model:', confirm: 'Done' };
|
|
28
|
+
export async function loadModelStrings() {
|
|
29
|
+
const i18n = await loadPluginI18n(new URL('../../locales/', import.meta.url));
|
|
30
|
+
return {
|
|
31
|
+
prompt: i18n.t('telegram.model.prompt', MODEL_STRINGS_FALLBACK.prompt),
|
|
32
|
+
confirm: i18n.t('telegram.model.confirm', MODEL_STRINGS_FALLBACK.confirm),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AgentDescriptor } from '@coffer-org/plugin-orchestrator/runtime';
|
|
2
|
+
import type { ThreadSelection } from '@coffer-org/server/thread-state';
|
|
3
|
+
export interface KeyboardButton {
|
|
4
|
+
text: string;
|
|
5
|
+
data: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function isModelCommand(text: string): boolean;
|
|
8
|
+
export declare function buildModelKeyboard(agents: AgentDescriptor[], selection: ThreadSelection): KeyboardButton[][];
|
|
9
|
+
export declare function parseModelCallback(data: string): {
|
|
10
|
+
agentId: string;
|
|
11
|
+
presetId: string;
|
|
12
|
+
} | null;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getLogger } from '@coffer-org/sdk/logger';
|
|
2
|
+
const log = getLogger('telegram');
|
|
3
|
+
const MODEL_COMMAND = /^\/model(@[a-z0-9_]{1,32})?(\s|$)/i;
|
|
4
|
+
export function isModelCommand(text) {
|
|
5
|
+
return MODEL_COMMAND.test(text.trim());
|
|
6
|
+
}
|
|
7
|
+
const CALLBACK_MAX_BYTES = 64;
|
|
8
|
+
function callbackBytes(data) {
|
|
9
|
+
return new TextEncoder().encode(data).length;
|
|
10
|
+
}
|
|
11
|
+
export function buildModelKeyboard(agents, selection) {
|
|
12
|
+
const multi = agents.length > 1;
|
|
13
|
+
return agents.flatMap((a) => a.presets.flatMap((p) => {
|
|
14
|
+
const data = `model:${a.id}:${p.id}`;
|
|
15
|
+
if (callbackBytes(data) > CALLBACK_MAX_BYTES) {
|
|
16
|
+
log.warn(`/model: skipping ${a.id}/${p.id} — callback data over ${CALLBACK_MAX_BYTES} bytes`);
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const current = a.id === selection.agentId && p.id === selection.presetId;
|
|
20
|
+
const label = multi ? `${a.title} · ${p.title}` : p.title;
|
|
21
|
+
return [[{ text: current ? `✓ ${label}` : label, data }]];
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
export function parseModelCallback(data) {
|
|
25
|
+
const parts = data.split(':');
|
|
26
|
+
if (parts.length !== 3 || parts[0] !== 'model')
|
|
27
|
+
return null;
|
|
28
|
+
const [, agentId, presetId] = parts;
|
|
29
|
+
if (!agentId || !presetId)
|
|
30
|
+
return null;
|
|
31
|
+
return { agentId, presetId };
|
|
32
|
+
}
|
package/dist/schema.js
CHANGED
|
@@ -4502,6 +4502,8 @@ function normalizeOpts(rawIn) {
|
|
|
4502
4502
|
unique: r.unique,
|
|
4503
4503
|
fixed: r.fixed,
|
|
4504
4504
|
exts: r.exts,
|
|
4505
|
+
ext: r.ext,
|
|
4506
|
+
maxBytes: r.maxBytes,
|
|
4505
4507
|
lead: r.lead,
|
|
4506
4508
|
by: r.by,
|
|
4507
4509
|
min: r.min,
|
|
@@ -4913,6 +4915,42 @@ function snippet(raw) {
|
|
|
4913
4915
|
}
|
|
4914
4916
|
});
|
|
4915
4917
|
}
|
|
4918
|
+
/** A NUL byte, or U+FFFD left behind by decoding non-UTF-8 bytes as text. */
|
|
4919
|
+
function isBinaryText(v) {
|
|
4920
|
+
return v.includes("\0") || v.includes("�");
|
|
4921
|
+
}
|
|
4922
|
+
function source(raw) {
|
|
4923
|
+
const o = normalizeOpts(raw);
|
|
4924
|
+
const required = o.required ?? false;
|
|
4925
|
+
const ext = o.ext ?? "txt";
|
|
4926
|
+
const maxBytes = o.maxBytes ?? 262144;
|
|
4927
|
+
const s = string$1(reqTypeErr()).superRefine((v, ctx) => {
|
|
4928
|
+
if (isBinaryText(v)) {
|
|
4929
|
+
ctx.addIssue({
|
|
4930
|
+
code: ZodIssueCode.custom,
|
|
4931
|
+
message: vmsg("source_binary")
|
|
4932
|
+
});
|
|
4933
|
+
return;
|
|
4934
|
+
}
|
|
4935
|
+
if (new TextEncoder().encode(v).length > maxBytes) ctx.addIssue({
|
|
4936
|
+
code: ZodIssueCode.custom,
|
|
4937
|
+
message: vmsg("source_too_large", { maxBytes })
|
|
4938
|
+
});
|
|
4939
|
+
});
|
|
4940
|
+
return wrapKey(o, {
|
|
4941
|
+
kind: "source",
|
|
4942
|
+
label: o.label ?? "",
|
|
4943
|
+
required,
|
|
4944
|
+
prim: "text",
|
|
4945
|
+
column: "text",
|
|
4946
|
+
hints: {
|
|
4947
|
+
ext,
|
|
4948
|
+
maxBytes,
|
|
4949
|
+
noEditControl: true
|
|
4950
|
+
},
|
|
4951
|
+
zod: optionalize(s, required)
|
|
4952
|
+
});
|
|
4953
|
+
}
|
|
4916
4954
|
function rating(raw) {
|
|
4917
4955
|
const o = normalizeOpts(raw);
|
|
4918
4956
|
const required = o.required ?? false;
|
|
@@ -5049,6 +5087,7 @@ var presets = {
|
|
|
5049
5087
|
tags,
|
|
5050
5088
|
markdown,
|
|
5051
5089
|
snippet,
|
|
5090
|
+
source,
|
|
5052
5091
|
rating,
|
|
5053
5092
|
duration,
|
|
5054
5093
|
reminder,
|
|
@@ -6349,11 +6388,18 @@ function triState(raw) {
|
|
|
6349
6388
|
zod: optionalize(s, required)
|
|
6350
6389
|
});
|
|
6351
6390
|
}
|
|
6391
|
+
/** Inline option entry → OptionItem (plain string = value and label at once). */
|
|
6392
|
+
function toOptionItem(o) {
|
|
6393
|
+
return typeof o === "string" ? {
|
|
6394
|
+
value: o,
|
|
6395
|
+
title: o
|
|
6396
|
+
} : o;
|
|
6397
|
+
}
|
|
6352
6398
|
function select(raw) {
|
|
6353
6399
|
const o = normalizeOpts(raw);
|
|
6354
6400
|
const required = o.required ?? false;
|
|
6355
6401
|
const source = typeof o.options === "string" ? o.options : null;
|
|
6356
|
-
const inlineOpts = Array.isArray(o.options) ? o.options : [];
|
|
6402
|
+
const inlineOpts = Array.isArray(o.options) ? o.options.map(toOptionItem) : [];
|
|
6357
6403
|
const s = inlineOpts.length > 0 ? _enum(inlineOpts.map((x) => x.value), { error: () => vmsg("enum") }) : string$1(reqErr());
|
|
6358
6404
|
return wrapKey(o, applyMultiple({
|
|
6359
6405
|
kind: "select",
|
|
@@ -6426,15 +6472,23 @@ function check(raw) {
|
|
|
6426
6472
|
const required = o.required ?? false;
|
|
6427
6473
|
const multiple = o.multiple ?? false;
|
|
6428
6474
|
const slots = o.slots && o.slots.length > 0 ? o.slots : [""];
|
|
6475
|
+
const contentFields = o.fields?.length ? o.fields : [string({
|
|
6476
|
+
key: "text",
|
|
6477
|
+
label: "core.fields.text"
|
|
6478
|
+
})];
|
|
6479
|
+
const contentKeys = /* @__PURE__ */ new Set();
|
|
6480
|
+
for (const f of contentFields) {
|
|
6481
|
+
if (contentKeys.has(f.key)) throw new Error(`[field.check] duplicate content field '${f.key}'`);
|
|
6482
|
+
if (/^check\d+$/.test(f.key)) throw new Error(`[field.check] content field '${f.key}' is reserved for checkbox slots`);
|
|
6483
|
+
if (!multiple && (f.type.virtual || f.type.columns)) throw new Error(`[field.check] single content field '${f.key}' must be a scalar stored field`);
|
|
6484
|
+
contentKeys.add(f.key);
|
|
6485
|
+
}
|
|
6486
|
+
const checkFields = slots.map((label, i) => boolean({
|
|
6487
|
+
key: `check${i}`,
|
|
6488
|
+
label: label || "core.fields.check"
|
|
6489
|
+
}));
|
|
6429
6490
|
if (multiple) {
|
|
6430
|
-
const fields =
|
|
6431
|
-
key: `check${i}`,
|
|
6432
|
-
label: label || "core.fields.check"
|
|
6433
|
-
}));
|
|
6434
|
-
fields.push(string({
|
|
6435
|
-
key: "text",
|
|
6436
|
-
label: "core.fields.text"
|
|
6437
|
-
}));
|
|
6491
|
+
const fields = [...checkFields, ...contentFields];
|
|
6438
6492
|
return group({
|
|
6439
6493
|
key: o.key,
|
|
6440
6494
|
label: o.label ?? o.key,
|
|
@@ -6444,8 +6498,12 @@ function check(raw) {
|
|
|
6444
6498
|
view: { kind: "checklist" }
|
|
6445
6499
|
});
|
|
6446
6500
|
}
|
|
6447
|
-
const shape = {
|
|
6448
|
-
const columns = {
|
|
6501
|
+
const shape = {};
|
|
6502
|
+
const columns = {};
|
|
6503
|
+
for (const f of contentFields) {
|
|
6504
|
+
shape[f.key] = f.type.zod;
|
|
6505
|
+
columns[f.key] = f.type.column;
|
|
6506
|
+
}
|
|
6449
6507
|
slots.forEach((_, i) => {
|
|
6450
6508
|
shape[`check${i}`] = boolean$1();
|
|
6451
6509
|
columns[`check${i}`] = "boolean";
|
|
@@ -6471,7 +6529,13 @@ function check(raw) {
|
|
|
6471
6529
|
required,
|
|
6472
6530
|
prim: "check",
|
|
6473
6531
|
column: "text",
|
|
6474
|
-
hints: {
|
|
6532
|
+
hints: {
|
|
6533
|
+
slots,
|
|
6534
|
+
fields: contentFields.map((f) => ({
|
|
6535
|
+
key: f.key,
|
|
6536
|
+
...toClient(f.type)
|
|
6537
|
+
}))
|
|
6538
|
+
},
|
|
6475
6539
|
columns,
|
|
6476
6540
|
zod: optionalize(s, required)
|
|
6477
6541
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coffer-org/plugin-telegram",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=24"
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"test": "node --import tsx --test \"src/runtime/*.test.ts\""
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@coffer-org/plugin-orchestrator": "^2.
|
|
29
|
-
"@coffer-org/sdk": "^2.1
|
|
30
|
-
"@coffer-org/server": "^2.
|
|
28
|
+
"@coffer-org/plugin-orchestrator": "^2.4.0",
|
|
29
|
+
"@coffer-org/sdk": "^2.2.1",
|
|
30
|
+
"@coffer-org/server": "^2.7.0",
|
|
31
31
|
"input": "^1.0.1",
|
|
32
32
|
"teleproto": "^1.228.1"
|
|
33
33
|
},
|