@kodelyth/tlon 2026.5.39 → 2026.5.42
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 +5 -0
- package/api.ts +16 -0
- package/channel-plugin-api.ts +1 -0
- package/dist/api.js +4 -0
- package/dist/channel-Bvzym9ez.js +236 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/channel.runtime-CDY2BdfM.js +3626 -0
- package/dist/doctor-contract-Ip6FcHDH.js +7 -0
- package/dist/doctor-contract-api.js +2 -0
- package/dist/index.js +18 -0
- package/dist/runtime-BmSb9A-q.js +8 -0
- package/dist/runtime-api-Dq8wkBC_.js +4 -0
- package/dist/runtime-api.js +2 -0
- package/dist/setup-api.js +3 -0
- package/dist/setup-core-CF3ryHqs.js +387 -0
- package/dist/setup-entry.js +11 -0
- package/dist/setup-surface-BM5_V_XL.js +74 -0
- package/dist/test-api.js +2 -0
- package/doctor-contract-api.ts +1 -0
- package/index.ts +16 -0
- package/klaw.plugin.json +3 -203
- package/package.json +4 -4
- package/runtime-api.ts +17 -0
- package/setup-api.ts +2 -0
- package/setup-entry.ts +9 -0
- package/src/account-fields.ts +31 -0
- package/src/channel.message-adapter.test.ts +145 -0
- package/src/channel.runtime.ts +259 -0
- package/src/channel.ts +192 -0
- package/src/config-schema.ts +54 -0
- package/src/core.test.ts +298 -0
- package/src/doctor-contract.ts +9 -0
- package/src/doctor.test.ts +46 -0
- package/src/doctor.ts +10 -0
- package/src/logger-runtime.ts +1 -0
- package/src/monitor/approval-runtime.ts +363 -0
- package/src/monitor/approval.test.ts +33 -0
- package/src/monitor/approval.ts +283 -0
- package/src/monitor/authorization.ts +30 -0
- package/src/monitor/cites.ts +54 -0
- package/src/monitor/discovery.ts +68 -0
- package/src/monitor/history.ts +226 -0
- package/src/monitor/index.ts +1523 -0
- package/src/monitor/media.test.ts +80 -0
- package/src/monitor/media.ts +156 -0
- package/src/monitor/processed-messages.test.ts +58 -0
- package/src/monitor/processed-messages.ts +89 -0
- package/src/monitor/settings-helpers.test.ts +113 -0
- package/src/monitor/settings-helpers.ts +158 -0
- package/src/monitor/utils.ts +402 -0
- package/src/runtime.ts +9 -0
- package/src/security.test.ts +658 -0
- package/src/session-route.ts +40 -0
- package/src/settings.ts +391 -0
- package/src/setup-core.ts +231 -0
- package/src/setup-surface.ts +99 -0
- package/src/targets.ts +102 -0
- package/src/tlon-api.test.ts +572 -0
- package/src/tlon-api.ts +389 -0
- package/src/types.ts +160 -0
- package/src/urbit/auth.ssrf.test.ts +45 -0
- package/src/urbit/auth.ts +48 -0
- package/src/urbit/base-url.test.ts +48 -0
- package/src/urbit/base-url.ts +61 -0
- package/src/urbit/channel-ops.test.ts +36 -0
- package/src/urbit/channel-ops.ts +149 -0
- package/src/urbit/context.ts +50 -0
- package/src/urbit/errors.ts +51 -0
- package/src/urbit/fetch.ts +38 -0
- package/src/urbit/foreigns.ts +49 -0
- package/src/urbit/send.test.ts +83 -0
- package/src/urbit/send.ts +228 -0
- package/src/urbit/sse-client.test.ts +234 -0
- package/src/urbit/sse-client.ts +492 -0
- package/src/urbit/story.ts +332 -0
- package/src/urbit/upload.test.ts +155 -0
- package/src/urbit/upload.ts +60 -0
- package/test-api.ts +1 -0
- package/tsconfig.json +16 -0
- package/api.js +0 -7
- package/bundled-skills/@tloncorp/tlon-skill/SKILL.md +0 -501
- package/bundled-skills/@tloncorp/tlon-skill/bin/tlon.js +0 -7
- package/bundled-skills/@tloncorp/tlon-skill/package.json +0 -40
- package/bundled-skills/@tloncorp/tlon-skill/scripts/postinstall.js +0 -7
- package/channel-plugin-api.js +0 -7
- package/doctor-contract-api.js +0 -7
- package/index.js +0 -7
- package/runtime-api.js +0 -7
- package/setup-api.js +0 -7
- package/setup-entry.js +0 -7
- package/test-api.js +0 -7
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveStableChannelMessageIngress,
|
|
3
|
+
type StableChannelIngressIdentityParams,
|
|
4
|
+
} from "klaw/plugin-sdk/channel-ingress-runtime";
|
|
5
|
+
import { formatErrorMessage as sharedFormatErrorMessage } from "klaw/plugin-sdk/error-runtime";
|
|
6
|
+
import { normalizeShip } from "../targets.js";
|
|
7
|
+
|
|
8
|
+
export interface ParsedCite {
|
|
9
|
+
type: "chan" | "group" | "desk" | "bait";
|
|
10
|
+
nest?: string;
|
|
11
|
+
author?: string;
|
|
12
|
+
postId?: string;
|
|
13
|
+
group?: string;
|
|
14
|
+
flag?: string;
|
|
15
|
+
where?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function extractCites(content: unknown): ParsedCite[] {
|
|
19
|
+
if (!content || !Array.isArray(content)) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const cites: ParsedCite[] = [];
|
|
24
|
+
|
|
25
|
+
for (const verse of content) {
|
|
26
|
+
if (verse?.block?.cite && typeof verse.block.cite === "object") {
|
|
27
|
+
const cite = verse.block.cite;
|
|
28
|
+
|
|
29
|
+
if (cite.chan && typeof cite.chan === "object") {
|
|
30
|
+
const { nest, where } = cite.chan;
|
|
31
|
+
const whereMatch = where?.match(/\/msg\/(~[a-z-]+)\/(.+)/);
|
|
32
|
+
cites.push({
|
|
33
|
+
type: "chan",
|
|
34
|
+
nest,
|
|
35
|
+
where,
|
|
36
|
+
author: whereMatch?.[1],
|
|
37
|
+
postId: whereMatch?.[2],
|
|
38
|
+
});
|
|
39
|
+
} else if (cite.group && typeof cite.group === "string") {
|
|
40
|
+
cites.push({ type: "group", group: cite.group });
|
|
41
|
+
} else if (cite.desk && typeof cite.desk === "object") {
|
|
42
|
+
cites.push({ type: "desk", flag: cite.desk.flag, where: cite.desk.where });
|
|
43
|
+
} else if (cite.bait && typeof cite.bait === "object") {
|
|
44
|
+
cites.push({
|
|
45
|
+
type: "bait",
|
|
46
|
+
group: cite.bait.group,
|
|
47
|
+
nest: cite.bait.graph,
|
|
48
|
+
where: cite.bait.where,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return cites;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function formatModelName(modelString?: string | null): string {
|
|
58
|
+
if (!modelString) {
|
|
59
|
+
return "AI";
|
|
60
|
+
}
|
|
61
|
+
const modelName = modelString.includes("/") ? modelString.split("/")[1] : modelString;
|
|
62
|
+
const modelMappings: Record<string, string> = {
|
|
63
|
+
"claude-opus-4-5": "Claude Opus 4.5",
|
|
64
|
+
"claude-sonnet-4-5": "Claude Sonnet 4.5",
|
|
65
|
+
"claude-sonnet-3-5": "Claude Sonnet 3.5",
|
|
66
|
+
"gpt-4o": "GPT-4o",
|
|
67
|
+
"gpt-4-turbo": "GPT-4 Turbo",
|
|
68
|
+
"gpt-4": "GPT-4",
|
|
69
|
+
"gemini-2.0-flash": "Gemini 2.0 Flash",
|
|
70
|
+
"gemini-pro": "Gemini Pro",
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if (modelMappings[modelName]) {
|
|
74
|
+
return modelMappings[modelName];
|
|
75
|
+
}
|
|
76
|
+
return modelName
|
|
77
|
+
.replace(/-/g, " ")
|
|
78
|
+
.split(" ")
|
|
79
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
80
|
+
.join(" ");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function isBotMentioned(
|
|
84
|
+
messageText: string,
|
|
85
|
+
botShipName: string,
|
|
86
|
+
nickname?: string,
|
|
87
|
+
): boolean {
|
|
88
|
+
if (!messageText || !botShipName) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (/@all\b/i.test(messageText)) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const normalizedBotShip = normalizeShip(botShipName);
|
|
97
|
+
const escapedShip = normalizedBotShip.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
98
|
+
const mentionPattern = new RegExp(`(^|\\s)${escapedShip}(?=\\s|$)`, "i");
|
|
99
|
+
if (mentionPattern.test(messageText)) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (nickname) {
|
|
104
|
+
const escapedNickname = nickname.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
105
|
+
const nicknamePattern = new RegExp(`(^|\\s)${escapedNickname}(?=\\s|$|[,!?.])`, "i");
|
|
106
|
+
if (nicknamePattern.test(messageText)) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function stripBotMention(messageText: string, botShipName: string): string {
|
|
115
|
+
if (!messageText || !botShipName) {
|
|
116
|
+
return messageText;
|
|
117
|
+
}
|
|
118
|
+
return messageText.replace(normalizeShip(botShipName), "").trim();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const tlonIngressIdentity = {
|
|
122
|
+
key: "sender-ship",
|
|
123
|
+
normalize: normalizeShip,
|
|
124
|
+
sensitivity: "pii",
|
|
125
|
+
isWildcardEntry: () => false,
|
|
126
|
+
entryIdPrefix: "tlon-entry",
|
|
127
|
+
} satisfies StableChannelIngressIdentityParams;
|
|
128
|
+
|
|
129
|
+
export async function isDmAllowedWithIngress(
|
|
130
|
+
senderShip: string,
|
|
131
|
+
allowlist: string[] | undefined,
|
|
132
|
+
): Promise<boolean> {
|
|
133
|
+
const access = await resolveStableChannelMessageIngress({
|
|
134
|
+
channelId: "tlon",
|
|
135
|
+
accountId: "default",
|
|
136
|
+
identity: tlonIngressIdentity,
|
|
137
|
+
subject: { stableId: senderShip },
|
|
138
|
+
conversation: {
|
|
139
|
+
kind: "direct",
|
|
140
|
+
id: "direct",
|
|
141
|
+
},
|
|
142
|
+
dmPolicy: "allowlist",
|
|
143
|
+
allowFrom: allowlist ?? [],
|
|
144
|
+
});
|
|
145
|
+
return access.senderAccess.allowed;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export async function resolveTlonCommandAuthorizationWithIngress(params: {
|
|
149
|
+
senderShip: string;
|
|
150
|
+
ownerShip: string | null | undefined;
|
|
151
|
+
useAccessGroups: boolean;
|
|
152
|
+
}) {
|
|
153
|
+
const normalizedOwner = params.ownerShip ? normalizeShip(params.ownerShip) : null;
|
|
154
|
+
return await resolveStableChannelMessageIngress({
|
|
155
|
+
channelId: "tlon",
|
|
156
|
+
accountId: "default",
|
|
157
|
+
identity: tlonIngressIdentity,
|
|
158
|
+
useAccessGroups: params.useAccessGroups,
|
|
159
|
+
subject: { stableId: params.senderShip },
|
|
160
|
+
conversation: {
|
|
161
|
+
kind: "direct",
|
|
162
|
+
id: "command",
|
|
163
|
+
},
|
|
164
|
+
event: {
|
|
165
|
+
authMode: "none",
|
|
166
|
+
mayPair: false,
|
|
167
|
+
},
|
|
168
|
+
dmPolicy: "allowlist",
|
|
169
|
+
groupPolicy: "open",
|
|
170
|
+
allowFrom: normalizedOwner ? [normalizedOwner] : [],
|
|
171
|
+
command: {},
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function isGroupInviteAllowed(
|
|
176
|
+
inviterShip: string,
|
|
177
|
+
allowlist: string[] | undefined,
|
|
178
|
+
): boolean {
|
|
179
|
+
if (!allowlist || allowlist.length === 0) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
const normalizedInviter = normalizeShip(inviterShip);
|
|
183
|
+
return allowlist.map((ship) => normalizeShip(ship)).some((ship) => ship === normalizedInviter);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export async function resolveAuthorizedMessageText(params: {
|
|
187
|
+
rawText: string;
|
|
188
|
+
content: unknown;
|
|
189
|
+
authorizedForCites: boolean;
|
|
190
|
+
resolveAllCites: (content: unknown) => Promise<string>;
|
|
191
|
+
}): Promise<string> {
|
|
192
|
+
const { rawText, content, authorizedForCites, resolveAllCites } = params;
|
|
193
|
+
if (!authorizedForCites) {
|
|
194
|
+
return rawText;
|
|
195
|
+
}
|
|
196
|
+
const citedContent = await resolveAllCites(content);
|
|
197
|
+
return citedContent + rawText;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export const asRecord = asNullableObjectRecord;
|
|
201
|
+
export const formatErrorMessage = sharedFormatErrorMessage;
|
|
202
|
+
export const readString = readStringField;
|
|
203
|
+
|
|
204
|
+
function asNullableObjectRecord(value: unknown): Record<string, unknown> | null {
|
|
205
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
206
|
+
? (value as Record<string, unknown>)
|
|
207
|
+
: null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function readStringField(
|
|
211
|
+
record: Record<string, unknown> | null | undefined,
|
|
212
|
+
field: string,
|
|
213
|
+
): string | undefined {
|
|
214
|
+
const value = record?.[field];
|
|
215
|
+
return typeof value === "string" ? value : undefined;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Helper to recursively extract text from inline content
|
|
219
|
+
function renderInlineItem(
|
|
220
|
+
item: unknown,
|
|
221
|
+
options?: {
|
|
222
|
+
linkMode?: "content-or-href" | "href";
|
|
223
|
+
allowBreak?: boolean;
|
|
224
|
+
allowBlockquote?: boolean;
|
|
225
|
+
},
|
|
226
|
+
): string {
|
|
227
|
+
if (typeof item === "string") {
|
|
228
|
+
return item;
|
|
229
|
+
}
|
|
230
|
+
const record = asRecord(item);
|
|
231
|
+
if (!record) {
|
|
232
|
+
return "";
|
|
233
|
+
}
|
|
234
|
+
const ship = readString(record, "ship");
|
|
235
|
+
if (ship) {
|
|
236
|
+
return ship;
|
|
237
|
+
}
|
|
238
|
+
if ("sect" in record) {
|
|
239
|
+
const sect = record.sect;
|
|
240
|
+
if (typeof sect === "string") {
|
|
241
|
+
return `@${sect || "all"}`;
|
|
242
|
+
}
|
|
243
|
+
if (sect === null) {
|
|
244
|
+
return "@all";
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (options?.allowBreak && "break" in record) {
|
|
248
|
+
return "\n";
|
|
249
|
+
}
|
|
250
|
+
const inlineCode = readString(record, "inline-code");
|
|
251
|
+
if (inlineCode) {
|
|
252
|
+
return `\`${inlineCode}\``;
|
|
253
|
+
}
|
|
254
|
+
const code = readString(record, "code");
|
|
255
|
+
if (code) {
|
|
256
|
+
return `\`${code}\``;
|
|
257
|
+
}
|
|
258
|
+
const link = asRecord(record.link);
|
|
259
|
+
const linkHref = link ? readString(link, "href") : undefined;
|
|
260
|
+
if (link && linkHref) {
|
|
261
|
+
const linkContent = readString(link, "content");
|
|
262
|
+
return options?.linkMode === "href" ? linkHref : linkContent || linkHref;
|
|
263
|
+
}
|
|
264
|
+
if (Array.isArray(record.bold)) {
|
|
265
|
+
return `**${extractInlineText(record.bold)}**`;
|
|
266
|
+
}
|
|
267
|
+
if (Array.isArray(record.italics)) {
|
|
268
|
+
return `*${extractInlineText(record.italics)}*`;
|
|
269
|
+
}
|
|
270
|
+
if (Array.isArray(record.strike)) {
|
|
271
|
+
return `~~${extractInlineText(record.strike)}~~`;
|
|
272
|
+
}
|
|
273
|
+
if (options?.allowBlockquote && Array.isArray(record.blockquote)) {
|
|
274
|
+
return `> ${extractInlineText(record.blockquote)}`;
|
|
275
|
+
}
|
|
276
|
+
return "";
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function extractInlineText(items: readonly unknown[]): string {
|
|
280
|
+
return items.map((item) => renderInlineItem(item)).join("");
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export function extractMessageText(content: unknown): string {
|
|
284
|
+
if (!content || !Array.isArray(content)) {
|
|
285
|
+
return "";
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return content
|
|
289
|
+
.map((verse) => {
|
|
290
|
+
const verseRecord = asRecord(verse);
|
|
291
|
+
if (!verseRecord) {
|
|
292
|
+
return "";
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Handle inline content (text, ships, links, etc.)
|
|
296
|
+
if (Array.isArray(verseRecord.inline)) {
|
|
297
|
+
return verseRecord.inline
|
|
298
|
+
.map((item) =>
|
|
299
|
+
renderInlineItem(item, {
|
|
300
|
+
linkMode: "href",
|
|
301
|
+
allowBreak: true,
|
|
302
|
+
allowBlockquote: true,
|
|
303
|
+
}),
|
|
304
|
+
)
|
|
305
|
+
.join("");
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Handle block content (images, code blocks, etc.)
|
|
309
|
+
const block = asRecord(verseRecord.block);
|
|
310
|
+
if (block) {
|
|
311
|
+
const image = asRecord(block.image);
|
|
312
|
+
|
|
313
|
+
// Image blocks
|
|
314
|
+
if (image) {
|
|
315
|
+
const imageSrc = readString(image, "src");
|
|
316
|
+
if (imageSrc) {
|
|
317
|
+
const altText = readString(image, "alt");
|
|
318
|
+
const alt = altText ? ` (${altText})` : "";
|
|
319
|
+
return `\n${imageSrc}${alt}\n`;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Code blocks
|
|
324
|
+
const codeBlock = asRecord(block.code);
|
|
325
|
+
if (codeBlock) {
|
|
326
|
+
const lang = readString(codeBlock, "lang") ?? "";
|
|
327
|
+
const code = readString(codeBlock, "code") ?? "";
|
|
328
|
+
return `\n\`\`\`${lang}\n${code}\n\`\`\`\n`;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Header blocks
|
|
332
|
+
const header = asRecord(block.header);
|
|
333
|
+
if (header) {
|
|
334
|
+
const headerContent = Array.isArray(header.content) ? header.content : [];
|
|
335
|
+
const text =
|
|
336
|
+
headerContent.map((item) => (typeof item === "string" ? item : "")).join("") || "";
|
|
337
|
+
return `\n## ${text}\n`;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Cite/quote blocks - parse the reference structure
|
|
341
|
+
const cite = asRecord(block.cite);
|
|
342
|
+
if (cite) {
|
|
343
|
+
const chanCite = asRecord(cite.chan);
|
|
344
|
+
|
|
345
|
+
// ChanCite - reference to a channel message
|
|
346
|
+
if (chanCite) {
|
|
347
|
+
const nest = readString(chanCite, "nest");
|
|
348
|
+
const where = readString(chanCite, "where");
|
|
349
|
+
// where is typically /msg/~author/timestamp
|
|
350
|
+
const whereMatch = where?.match(/\/msg\/(~[a-z-]+)\/(.+)/);
|
|
351
|
+
if (whereMatch) {
|
|
352
|
+
const [, author, _postId] = whereMatch;
|
|
353
|
+
return `\n> [quoted: ${author} in ${nest}]\n`;
|
|
354
|
+
}
|
|
355
|
+
return `\n> [quoted from ${nest}]\n`;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// GroupCite - reference to a group
|
|
359
|
+
const group = readString(cite, "group");
|
|
360
|
+
if (group) {
|
|
361
|
+
return `\n> [ref: group ${group}]\n`;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// DeskCite - reference to an app/desk
|
|
365
|
+
const desk = asRecord(cite.desk);
|
|
366
|
+
if (desk) {
|
|
367
|
+
const flag = readString(desk, "flag");
|
|
368
|
+
if (flag) {
|
|
369
|
+
return `\n> [ref: ${flag}]\n`;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// BaitCite - reference with group+graph context
|
|
374
|
+
const bait = asRecord(cite.bait);
|
|
375
|
+
if (bait) {
|
|
376
|
+
const graph = readString(bait, "graph");
|
|
377
|
+
const groupName = readString(bait, "group");
|
|
378
|
+
if (graph && groupName) {
|
|
379
|
+
return `\n> [ref: ${graph} in ${groupName}]\n`;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return `\n> [quoted message]\n`;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return "";
|
|
388
|
+
})
|
|
389
|
+
.join("\n")
|
|
390
|
+
.trim();
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export function isSummarizationRequest(messageText: string): boolean {
|
|
394
|
+
const patterns = [
|
|
395
|
+
/summarize\s+(this\s+)?(channel|chat|conversation)/i,
|
|
396
|
+
/what\s+did\s+i\s+miss/i,
|
|
397
|
+
/catch\s+me\s+up/i,
|
|
398
|
+
/channel\s+summary/i,
|
|
399
|
+
/tldr/i,
|
|
400
|
+
];
|
|
401
|
+
return patterns.some((pattern) => pattern.test(messageText));
|
|
402
|
+
}
|
package/src/runtime.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PluginRuntime } from "klaw/plugin-sdk/plugin-runtime";
|
|
2
|
+
import { createPluginRuntimeStore } from "klaw/plugin-sdk/runtime-store";
|
|
3
|
+
|
|
4
|
+
const { setRuntime: setTlonRuntime, getRuntime: getTlonRuntime } =
|
|
5
|
+
createPluginRuntimeStore<PluginRuntime>({
|
|
6
|
+
pluginId: "tlon",
|
|
7
|
+
errorMessage: "Tlon runtime not initialized",
|
|
8
|
+
});
|
|
9
|
+
export { getTlonRuntime, setTlonRuntime };
|