@rubytech/create-realagent 1.0.426 → 1.0.429
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/index.js +82 -37
- package/package.json +3 -3
- package/payload/maxy/package.json +1 -1
- package/payload/maxy/public/assets/{admin-h_MCGiva.js → admin-CvVTy3NI.js} +1 -1
- package/payload/maxy/public/brand/favicon.ico +0 -0
- package/payload/maxy/public/brand-constants.json +6 -6
- package/payload/maxy/public/brand-defaults.css +5 -5
- package/payload/maxy/public/index.html +2 -2
- package/payload/maxy/public/public.html +1 -1
- package/payload/maxy/server.js +29 -9
- package/payload/platform/config/brand.json +20 -22
- package/payload/platform/plugins/telegram/PLUGIN.md +34 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.js +101 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.d.ts +27 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.js +41 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.d.ts +16 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js +62 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts +20 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message.js +34 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/package.json +19 -0
- package/payload/platform/plugins/telegram/references/setup-guide.md +50 -0
- package/payload/platform/scripts/vnc.sh +20 -1
- package/payload/maxy/public/brand/demo-9pm-enquiry.svg +0 -95
- package/payload/maxy/public/brand/demo-create-agent.svg +0 -110
- package/payload/maxy/public/brand/demo-morning-briefing.svg +0 -83
- package/payload/maxy/public/brand/demo-post-viewing.svg +0 -107
- package/payload/maxy/public/brand/how-it-works.svg +0 -152
- package/payload/maxy/public/brand/realagent-favicon-dark-32.png +0 -0
- package/payload/maxy/public/brand/realagent-icon-dark-round-web.png +0 -0
- package/payload/maxy/public/brand/realagent-icon-dark-web.png +0 -0
- package/payload/maxy/public/brand/realagent-icon-web.png +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
:root {
|
|
2
|
-
/* Brand defaults — generated by bundle.js from brands/
|
|
2
|
+
/* Brand defaults — generated by bundle.js from brands/maxy/brand.json */
|
|
3
3
|
--sage: #7C8C72;
|
|
4
4
|
--sage-hover: #6A7A62;
|
|
5
5
|
--sage-subtle: rgba(124, 140, 114, 0.08);
|
|
6
6
|
--sage-glow: rgba(124, 140, 114, 0.15);
|
|
7
|
-
--visitor-bubble: #
|
|
7
|
+
--visitor-bubble: #E8ECF0;
|
|
8
8
|
--bg: #FAFAF8;
|
|
9
|
-
--maxy-bubble: #
|
|
10
|
-
--font-display: '
|
|
11
|
-
--font-body: '
|
|
9
|
+
--maxy-bubble: #F5F2ED;
|
|
10
|
+
--font-display: 'Cormorant', Georgia, serif;
|
|
11
|
+
--font-body: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
12
12
|
}
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>
|
|
6
|
+
<title>Maxy</title>
|
|
7
7
|
<link rel="icon" href="/favicon.ico">
|
|
8
|
-
<script type="module" crossorigin src="/assets/admin-
|
|
8
|
+
<script type="module" crossorigin src="/assets/admin-CvVTy3NI.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/ChatInput-Bkvp46jn.js">
|
|
10
10
|
<link rel="stylesheet" crossorigin href="/assets/ChatInput-BcuvuN5M.css">
|
|
11
11
|
<link rel="stylesheet" href="/brand-defaults.css">
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>
|
|
6
|
+
<title>Maxy</title>
|
|
7
7
|
<link rel="icon" href="/favicon.ico">
|
|
8
8
|
<script type="module" crossorigin src="/assets/public-CJdTPrH1.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/ChatInput-Bkvp46jn.js">
|
package/payload/maxy/server.js
CHANGED
|
@@ -3191,9 +3191,6 @@ async function ensureCdp() {
|
|
|
3191
3191
|
}
|
|
3192
3192
|
return waitForPort(9222, 12e3);
|
|
3193
3193
|
}
|
|
3194
|
-
function killChromium() {
|
|
3195
|
-
spawnSync("pkill", ["-f", "chromium"], { stdio: "pipe" });
|
|
3196
|
-
}
|
|
3197
3194
|
function writeChromiumWrapper() {
|
|
3198
3195
|
mkdirSync(BIN_DIR, { recursive: true });
|
|
3199
3196
|
const wrapperPath = resolve2(BIN_DIR, "chromium");
|
|
@@ -3235,6 +3232,9 @@ nohup "$BIN" \\
|
|
|
3235
3232
|
--ozone-platform=x11 \\
|
|
3236
3233
|
--no-first-run \\
|
|
3237
3234
|
--no-default-browser-check \\
|
|
3235
|
+
--disable-session-crashed-bubble \\
|
|
3236
|
+
--hide-crash-restore-bubble \\
|
|
3237
|
+
--noerrdialogs \\
|
|
3238
3238
|
--window-size=1280,800 \\
|
|
3239
3239
|
--window-position=0,0 \\
|
|
3240
3240
|
"$@" >> "$LOG" 2>&1 &
|
|
@@ -9062,6 +9062,22 @@ function checkAuthStatus() {
|
|
|
9062
9062
|
return false;
|
|
9063
9063
|
}
|
|
9064
9064
|
}
|
|
9065
|
+
async function waitForAuthPage(timeoutMs = 2e4) {
|
|
9066
|
+
const deadline = Date.now() + timeoutMs;
|
|
9067
|
+
while (Date.now() < deadline) {
|
|
9068
|
+
try {
|
|
9069
|
+
const res = await fetch("http://127.0.0.1:9222/json/list");
|
|
9070
|
+
const pages = await res.json();
|
|
9071
|
+
const hasContent = pages.some(
|
|
9072
|
+
(p) => p.type === "page" && p.url && p.url !== "about:blank"
|
|
9073
|
+
);
|
|
9074
|
+
if (hasContent) return true;
|
|
9075
|
+
} catch {
|
|
9076
|
+
}
|
|
9077
|
+
await sleep(500);
|
|
9078
|
+
}
|
|
9079
|
+
return false;
|
|
9080
|
+
}
|
|
9065
9081
|
async function GET2() {
|
|
9066
9082
|
return Response.json({ authenticated: checkAuthStatus() });
|
|
9067
9083
|
}
|
|
@@ -9072,7 +9088,6 @@ async function POST9(req) {
|
|
|
9072
9088
|
} catch {
|
|
9073
9089
|
}
|
|
9074
9090
|
if (body.action === "stop") {
|
|
9075
|
-
killChromium();
|
|
9076
9091
|
return Response.json({ stopped: true });
|
|
9077
9092
|
}
|
|
9078
9093
|
if (body.action === "logout") {
|
|
@@ -9084,18 +9099,23 @@ async function POST9(req) {
|
|
|
9084
9099
|
}
|
|
9085
9100
|
if (body.action === "wait") {
|
|
9086
9101
|
const authenticated = checkAuthStatus();
|
|
9087
|
-
if (authenticated) killChromium();
|
|
9088
9102
|
return Response.json({ completed: authenticated, authenticated });
|
|
9089
9103
|
}
|
|
9104
|
+
if (body.action === "launch-browser") {
|
|
9105
|
+
const vncReady2 = await ensureVnc();
|
|
9106
|
+
if (!vncReady2) {
|
|
9107
|
+
return Response.json({ error: "VNC display failed to start" }, { status: 500 });
|
|
9108
|
+
}
|
|
9109
|
+
const cdpReady = await ensureCdp();
|
|
9110
|
+
return Response.json({ launched: cdpReady });
|
|
9111
|
+
}
|
|
9090
9112
|
ensureLogDir();
|
|
9091
|
-
killChromium();
|
|
9092
|
-
await sleep(400);
|
|
9093
9113
|
const vncReady = await ensureVnc();
|
|
9094
9114
|
if (!vncReady) {
|
|
9095
9115
|
return Response.json({ error: "VNC display failed to start" }, { status: 500 });
|
|
9096
9116
|
}
|
|
9117
|
+
await ensureCdp();
|
|
9097
9118
|
writeFileSync6(logPath("claude-auth"), "");
|
|
9098
|
-
writeFileSync6(logPath("chromium"), "");
|
|
9099
9119
|
const chromiumWrapper = writeChromiumWrapper();
|
|
9100
9120
|
const x11Env = buildX11Env(chromiumWrapper);
|
|
9101
9121
|
const claudeAuthLogFd = openSync(logPath("claude-auth"), "a");
|
|
@@ -9108,7 +9128,7 @@ async function POST9(req) {
|
|
|
9108
9128
|
claudeProc.stdout?.on("data", onClaudeOutput);
|
|
9109
9129
|
claudeProc.stderr?.on("data", onClaudeOutput);
|
|
9110
9130
|
claudeProc.once("close", () => closeSync(claudeAuthLogFd));
|
|
9111
|
-
await
|
|
9131
|
+
await waitForAuthPage(2e4);
|
|
9112
9132
|
return Response.json({ started: true });
|
|
9113
9133
|
}
|
|
9114
9134
|
|
|
@@ -1,45 +1,43 @@
|
|
|
1
1
|
{
|
|
2
|
-
"productName": "
|
|
3
|
-
"hostname": "
|
|
4
|
-
"serviceName": "
|
|
5
|
-
"installDir": "
|
|
6
|
-
"configDir": ".
|
|
7
|
-
"tagline": "
|
|
8
|
-
"
|
|
9
|
-
"domain": "
|
|
2
|
+
"productName": "Maxy",
|
|
3
|
+
"hostname": "maxy",
|
|
4
|
+
"serviceName": "maxy.service",
|
|
5
|
+
"installDir": "maxy",
|
|
6
|
+
"configDir": ".maxy",
|
|
7
|
+
"tagline": "AI for Productive People",
|
|
8
|
+
"strapline": "Convenience as standard.",
|
|
9
|
+
"domain": "getmaxy.com",
|
|
10
10
|
|
|
11
11
|
"defaultColors": {
|
|
12
12
|
"primary": "#7C8C72",
|
|
13
13
|
"primaryHover": "#6A7A62",
|
|
14
14
|
"primarySubtle": "rgba(124, 140, 114, 0.08)",
|
|
15
15
|
"primaryGlow": "rgba(124, 140, 114, 0.15)",
|
|
16
|
-
"accent": "#
|
|
16
|
+
"accent": "#E8ECF0",
|
|
17
17
|
"background": "#FAFAF8",
|
|
18
|
-
"agentBubble": "#
|
|
18
|
+
"agentBubble": "#F5F2ED"
|
|
19
19
|
},
|
|
20
20
|
|
|
21
21
|
"defaultFonts": {
|
|
22
|
-
"display": "'
|
|
23
|
-
"body": "'
|
|
22
|
+
"display": "'Cormorant', Georgia, serif",
|
|
23
|
+
"body": "'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif"
|
|
24
24
|
},
|
|
25
25
|
|
|
26
26
|
"assets": {
|
|
27
|
-
"logo": "
|
|
28
|
-
"
|
|
29
|
-
"logoRound": "realagent-icon-dark-round-web.png",
|
|
30
|
-
"favicon": "realagent-favicon-dark-32.png"
|
|
27
|
+
"logo": "maxy-monochrome.png",
|
|
28
|
+
"favicon": "favicon.ico"
|
|
31
29
|
},
|
|
32
30
|
|
|
33
31
|
"npm": {
|
|
34
|
-
"packageName": "@rubytech/create-
|
|
35
|
-
"binName": "create-
|
|
32
|
+
"packageName": "@rubytech/create-maxy",
|
|
33
|
+
"binName": "create-maxy",
|
|
36
34
|
"author": "Rubytech LLC"
|
|
37
35
|
},
|
|
38
36
|
|
|
39
37
|
"plugins": {
|
|
40
|
-
"core": ["admin", "memory", "docs", "cloudflare", "anthropic", "workflows", "tasks"
|
|
41
|
-
"defaultEnabled": ["
|
|
42
|
-
"available": ["
|
|
43
|
-
"excluded": [
|
|
38
|
+
"core": ["admin", "memory", "docs", "cloudflare", "anthropic", "workflows", "tasks"],
|
|
39
|
+
"defaultEnabled": ["business-assistant", "sales", "contacts", "email", "scheduling", "projects"],
|
|
40
|
+
"available": ["telegram", "waitlist", "deep-research"],
|
|
41
|
+
"excluded": []
|
|
44
42
|
}
|
|
45
43
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: telegram
|
|
3
|
+
description: Guide users through connecting a Telegram bot — creating a bot via BotFather, finding user IDs, and configuring admin vs public bots.
|
|
4
|
+
metadata: {"taskmaster":{"optional":true}}
|
|
5
|
+
tools:
|
|
6
|
+
- message
|
|
7
|
+
- message-history
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Telegram Setup
|
|
11
|
+
|
|
12
|
+
Walks users through connecting Telegram bots to Taskmaster. Covers bot creation, token configuration, finding numeric user IDs, and choosing between admin and public bot roles.
|
|
13
|
+
|
|
14
|
+
## When to activate
|
|
15
|
+
|
|
16
|
+
- User asks how to connect Telegram or set up a Telegram bot
|
|
17
|
+
- User asks about BotFather, bot tokens, or Telegram integration
|
|
18
|
+
- User needs to find their Telegram user ID for admin binding
|
|
19
|
+
- User asks about admin vs public bot configuration
|
|
20
|
+
- User is on the Setup page and asks about the Telegram section
|
|
21
|
+
|
|
22
|
+
## What it unlocks
|
|
23
|
+
|
|
24
|
+
- Telegram as a messaging channel — DMs and group conversations routed to the AI assistant
|
|
25
|
+
- Multi-bot support — separate admin and public bots with different access policies
|
|
26
|
+
- Admin routing — restrict a bot to admin-only access via numeric user ID bindings
|
|
27
|
+
|
|
28
|
+
## References
|
|
29
|
+
|
|
30
|
+
| Task | When to use | Reference |
|
|
31
|
+
|------|-------------|-----------|
|
|
32
|
+
| Guided setup | User wants help connecting Telegram | `references/setup-guide.md` |
|
|
33
|
+
|
|
34
|
+
Load the reference and follow its instructions.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { message } from "./tools/message.js";
|
|
5
|
+
import { messageHistory } from "./tools/message-history.js";
|
|
6
|
+
const server = new McpServer({
|
|
7
|
+
name: "maxy-messaging",
|
|
8
|
+
version: "0.1.0",
|
|
9
|
+
});
|
|
10
|
+
server.tool("message", "Send a message via Telegram. Supports text with HTML formatting and inline keyboards for interactive choices.", {
|
|
11
|
+
channel: z.literal("telegram").describe("Delivery channel"),
|
|
12
|
+
chatId: z
|
|
13
|
+
.union([z.string(), z.number()])
|
|
14
|
+
.describe("Telegram chat ID to send to"),
|
|
15
|
+
text: z.string().describe("Message text (HTML formatting supported)"),
|
|
16
|
+
parseMode: z
|
|
17
|
+
.enum(["HTML", "Markdown", "MarkdownV2"])
|
|
18
|
+
.optional()
|
|
19
|
+
.describe("Parse mode (default: HTML)"),
|
|
20
|
+
inlineKeyboard: z
|
|
21
|
+
.array(z.array(z.object({
|
|
22
|
+
text: z.string().describe("Button label"),
|
|
23
|
+
callbackData: z
|
|
24
|
+
.string()
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Callback data for button press"),
|
|
27
|
+
url: z.string().optional().describe("URL to open on button press"),
|
|
28
|
+
})))
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Inline keyboard rows for interactive buttons"),
|
|
31
|
+
}, async (params) => {
|
|
32
|
+
try {
|
|
33
|
+
const result = await message(params);
|
|
34
|
+
if (!result.sent) {
|
|
35
|
+
return {
|
|
36
|
+
content: [
|
|
37
|
+
{
|
|
38
|
+
type: "text",
|
|
39
|
+
text: `Message failed: ${result.error}`,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
isError: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
content: [
|
|
47
|
+
{
|
|
48
|
+
type: "text",
|
|
49
|
+
text: `Message sent via ${result.channel} (ID: ${result.messageId})`,
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: "text",
|
|
59
|
+
text: `Send failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
isError: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
server.tool("message-history", "Query conversation history from the message log.", {
|
|
67
|
+
channel: z.string().optional().describe("Filter by channel (telegram)"),
|
|
68
|
+
chatId: z.string().optional().describe("Filter by chat ID"),
|
|
69
|
+
limit: z.number().optional().describe("Max messages to return (default 20)"),
|
|
70
|
+
}, async ({ channel, chatId, limit }) => {
|
|
71
|
+
try {
|
|
72
|
+
const history = await messageHistory({ channel, chatId, limit });
|
|
73
|
+
if (history.length === 0) {
|
|
74
|
+
return {
|
|
75
|
+
content: [
|
|
76
|
+
{ type: "text", text: "No message history found." },
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const formatted = history
|
|
81
|
+
.map((h) => `[${h.timestamp}] ${h.channel}/${h.chatId} (${h.role}): ${h.content.slice(0, 200)}${h.content.length > 200 ? "..." : ""}`)
|
|
82
|
+
.join("\n");
|
|
83
|
+
return {
|
|
84
|
+
content: [{ type: "text", text: formatted }],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
return {
|
|
89
|
+
content: [
|
|
90
|
+
{
|
|
91
|
+
type: "text",
|
|
92
|
+
text: `History query failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
isError: true,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
const transport = new StdioServerTransport();
|
|
100
|
+
await server.connect(transport);
|
|
101
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,gBAAgB;IACtB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,MAAM,CAAC,IAAI,CACT,SAAS,EACT,+GAA+G,EAC/G;IACE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IAC3D,MAAM,EAAE,CAAC;SACN,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;SAC/B,QAAQ,CAAC,6BAA6B,CAAC;IAC1C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;IACrE,SAAS,EAAE,CAAC;SACT,IAAI,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;SACxC,QAAQ,EAAE;SACV,QAAQ,CAAC,4BAA4B,CAAC;IACzC,cAAc,EAAE,CAAC;SACd,KAAK,CACJ,CAAC,CAAC,KAAK,CACL,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;QACzC,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,gCAAgC,CAAC;QAC7C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;KACnE,CAAC,CACH,CACF;SACA,QAAQ,EAAE;SACV,QAAQ,CAAC,8CAA8C,CAAC;CAC5D,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;IACf,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;QAErC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,mBAAmB,MAAM,CAAC,KAAK,EAAE;qBACxC;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,oBAAoB,MAAM,CAAC,OAAO,SAAS,MAAM,CAAC,SAAS,GAAG;iBACrE;aACF;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,gBAAgB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;iBACzE;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,kDAAkD,EAClD;IACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;IACvE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IAC3D,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;CAC7E,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;IACnC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAEjE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO;gBACL,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,2BAA2B,EAAE;iBAC7D;aACF,CAAC;QACJ,CAAC;QAED,MAAM,SAAS,GAAG,OAAO;aACtB,GAAG,CACF,CAAC,CAAC,EAAE,EAAE,CACJ,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAC5H;aACA,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;SACtD,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,yBAAyB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;iBAClF;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface TelegramSendOptions {
|
|
2
|
+
chatId: string | number;
|
|
3
|
+
text: string;
|
|
4
|
+
parseMode?: "HTML" | "Markdown" | "MarkdownV2";
|
|
5
|
+
replyMarkup?: TelegramInlineKeyboard;
|
|
6
|
+
}
|
|
7
|
+
export interface TelegramInlineKeyboard {
|
|
8
|
+
inline_keyboard: Array<Array<{
|
|
9
|
+
text: string;
|
|
10
|
+
callback_data?: string;
|
|
11
|
+
url?: string;
|
|
12
|
+
}>>;
|
|
13
|
+
}
|
|
14
|
+
export declare function sendMessage(botToken: string, options: TelegramSendOptions): Promise<{
|
|
15
|
+
ok: boolean;
|
|
16
|
+
messageId?: number;
|
|
17
|
+
error?: string;
|
|
18
|
+
}>;
|
|
19
|
+
export declare function setWebhook(botToken: string, webhookUrl: string): Promise<{
|
|
20
|
+
ok: boolean;
|
|
21
|
+
error?: string;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function getWebhookInfo(botToken: string): Promise<{
|
|
24
|
+
url: string;
|
|
25
|
+
pendingUpdateCount: number;
|
|
26
|
+
}>;
|
|
27
|
+
//# sourceMappingURL=telegram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../src/lib/telegram.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,YAAY,CAAC;IAC/C,WAAW,CAAC,EAAE,sBAAsB,CAAC;CACtC;AAED,MAAM,WAAW,sBAAsB;IACrC,eAAe,EAAE,KAAK,CACpB,KAAK,CAAC;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC,CACH,CAAC;CACH;AAED,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAyB9D;AAED,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiB1C;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAE,CAAC,CAWtD"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const TELEGRAM_API = "https://api.telegram.org";
|
|
2
|
+
export async function sendMessage(botToken, options) {
|
|
3
|
+
const res = await fetch(`${TELEGRAM_API}/bot${botToken}/sendMessage`, {
|
|
4
|
+
method: "POST",
|
|
5
|
+
headers: { "Content-Type": "application/json" },
|
|
6
|
+
body: JSON.stringify({
|
|
7
|
+
chat_id: options.chatId,
|
|
8
|
+
text: options.text,
|
|
9
|
+
parse_mode: options.parseMode ?? "HTML",
|
|
10
|
+
reply_markup: options.replyMarkup
|
|
11
|
+
? JSON.stringify(options.replyMarkup)
|
|
12
|
+
: undefined,
|
|
13
|
+
}),
|
|
14
|
+
});
|
|
15
|
+
const data = (await res.json());
|
|
16
|
+
if (!data.ok) {
|
|
17
|
+
return { ok: false, error: data.description ?? "Unknown Telegram error" };
|
|
18
|
+
}
|
|
19
|
+
return { ok: true, messageId: data.result?.message_id };
|
|
20
|
+
}
|
|
21
|
+
export async function setWebhook(botToken, webhookUrl) {
|
|
22
|
+
const res = await fetch(`${TELEGRAM_API}/bot${botToken}/setWebhook`, {
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: { "Content-Type": "application/json" },
|
|
25
|
+
body: JSON.stringify({ url: webhookUrl }),
|
|
26
|
+
});
|
|
27
|
+
const data = (await res.json());
|
|
28
|
+
if (!data.ok) {
|
|
29
|
+
return { ok: false, error: data.description ?? "Failed to set webhook" };
|
|
30
|
+
}
|
|
31
|
+
return { ok: true };
|
|
32
|
+
}
|
|
33
|
+
export async function getWebhookInfo(botToken) {
|
|
34
|
+
const res = await fetch(`${TELEGRAM_API}/bot${botToken}/getWebhookInfo`);
|
|
35
|
+
const data = (await res.json());
|
|
36
|
+
return {
|
|
37
|
+
url: data.result.url,
|
|
38
|
+
pendingUpdateCount: data.result.pending_update_count,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=telegram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../src/lib/telegram.ts"],"names":[],"mappings":"AAAA,MAAM,YAAY,GAAG,0BAA0B,CAAC;AAmBhD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAgB,EAChB,OAA4B;IAE5B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,YAAY,OAAO,QAAQ,cAAc,EAAE;QACpE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,OAAO,EAAE,OAAO,CAAC,MAAM;YACvB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,UAAU,EAAE,OAAO,CAAC,SAAS,IAAI,MAAM;YACvC,YAAY,EAAE,OAAO,CAAC,WAAW;gBAC/B,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC;gBACrC,CAAC,CAAC,SAAS;SACd,CAAC;KACH,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAI7B,CAAC;IAEF,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,IAAI,wBAAwB,EAAE,CAAC;IAC5E,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,QAAgB,EAChB,UAAkB;IAElB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,YAAY,OAAO,QAAQ,aAAa,EAAE;QACnE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;KAC1C,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAG7B,CAAC;IAEF,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,IAAI,uBAAuB,EAAE,CAAC;IAC3E,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,GAAG,YAAY,OAAO,QAAQ,iBAAiB,CAChD,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAE7B,CAAC;IACF,OAAO;QACL,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG;QACpB,kBAAkB,EAAE,IAAI,CAAC,MAAM,CAAC,oBAAoB;KACrD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface HistoryParams {
|
|
2
|
+
channel?: string;
|
|
3
|
+
chatId?: string;
|
|
4
|
+
accountId?: string;
|
|
5
|
+
limit?: number;
|
|
6
|
+
}
|
|
7
|
+
interface HistoryEntry {
|
|
8
|
+
channel: string;
|
|
9
|
+
chatId: string;
|
|
10
|
+
role: string;
|
|
11
|
+
content: string;
|
|
12
|
+
timestamp: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function messageHistory(params: HistoryParams): Promise<HistoryEntry[]>;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=message-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-history.d.ts","sourceRoot":"","sources":["../../src/tools/message-history.ts"],"names":[],"mappings":"AAiCA,UAAU,aAAa;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,YAAY,EAAE,CAAC,CAyCzB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import neo4j from "neo4j-driver";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
let driver = null;
|
|
5
|
+
function readPassword() {
|
|
6
|
+
if (process.env.NEO4J_PASSWORD)
|
|
7
|
+
return process.env.NEO4J_PASSWORD;
|
|
8
|
+
const passwordFile = resolve(process.env.PLATFORM_ROOT ?? resolve(import.meta.dirname, "../../../.."), "config/.neo4j-password");
|
|
9
|
+
try {
|
|
10
|
+
return readFileSync(passwordFile, "utf-8").trim();
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw new Error(`Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function getSession() {
|
|
17
|
+
if (!driver) {
|
|
18
|
+
const uri = process.env.NEO4J_URI ?? "bolt://localhost:7687";
|
|
19
|
+
const user = process.env.NEO4J_USER ?? "neo4j";
|
|
20
|
+
const password = readPassword();
|
|
21
|
+
driver = neo4j.driver(uri, neo4j.auth.basic(user, password));
|
|
22
|
+
}
|
|
23
|
+
return driver.session();
|
|
24
|
+
}
|
|
25
|
+
export async function messageHistory(params) {
|
|
26
|
+
const { channel, chatId, accountId, limit = 20 } = params;
|
|
27
|
+
const session = getSession();
|
|
28
|
+
try {
|
|
29
|
+
const conditions = ["m.accountId = $accountId"];
|
|
30
|
+
const queryParams = { accountId, limit };
|
|
31
|
+
if (channel) {
|
|
32
|
+
conditions.push("m.channel = $channel");
|
|
33
|
+
queryParams.channel = channel;
|
|
34
|
+
}
|
|
35
|
+
if (chatId) {
|
|
36
|
+
conditions.push("m.chatId = $chatId");
|
|
37
|
+
queryParams.chatId = chatId;
|
|
38
|
+
}
|
|
39
|
+
const query = `
|
|
40
|
+
MATCH (m:Communication)
|
|
41
|
+
WHERE ${conditions.join(" AND ")}
|
|
42
|
+
RETURN m
|
|
43
|
+
ORDER BY m.dateSent DESC
|
|
44
|
+
LIMIT $limit
|
|
45
|
+
`;
|
|
46
|
+
const result = await session.run(query, queryParams);
|
|
47
|
+
return result.records.map((record) => {
|
|
48
|
+
const m = record.get("m").properties;
|
|
49
|
+
return {
|
|
50
|
+
channel: m.channel,
|
|
51
|
+
chatId: m.chatId,
|
|
52
|
+
role: m.role,
|
|
53
|
+
content: m.content,
|
|
54
|
+
timestamp: m.dateSent,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
await session.close();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=message-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-history.js","sourceRoot":"","sources":["../../src/tools/message-history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC,SAAS,YAAY;IACnB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAElE,MAAM,YAAY,GAAG,OAAO,CAC1B,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,EACxE,wBAAwB,CACzB,CAAC;IAEF,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,yCAAyC,YAAY,gCAAgC,CACtF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,UAAU;IACjB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,uBAAuB,CAAC;QAC7D,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC;QAC/C,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;AAC1B,CAAC;AAiBD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAqB;IAErB,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC;IAE1D,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,CAAC,0BAA0B,CAAC,CAAC;QAChD,MAAM,WAAW,GAA4B,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAElE,IAAI,OAAO,EAAE,CAAC;YACZ,UAAU,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YACxC,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC;QAChC,CAAC;QACD,IAAI,MAAM,EAAE,CAAC;YACX,UAAU,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;YACtC,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC;QAC9B,CAAC;QAED,MAAM,KAAK,GAAG;;cAEJ,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;;;;KAIjC,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QAErD,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YACnC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC;YACrC,OAAO;gBACL,OAAO,EAAE,CAAC,CAAC,OAAiB;gBAC5B,MAAM,EAAE,CAAC,CAAC,MAAgB;gBAC1B,IAAI,EAAE,CAAC,CAAC,IAAc;gBACtB,OAAO,EAAE,CAAC,CAAC,OAAiB;gBAC5B,SAAS,EAAE,CAAC,CAAC,QAAkB;aAChC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface MessageParams {
|
|
2
|
+
channel: "telegram";
|
|
3
|
+
chatId: string | number;
|
|
4
|
+
text: string;
|
|
5
|
+
parseMode?: "HTML" | "Markdown" | "MarkdownV2";
|
|
6
|
+
inlineKeyboard?: Array<Array<{
|
|
7
|
+
text: string;
|
|
8
|
+
callbackData?: string;
|
|
9
|
+
url?: string;
|
|
10
|
+
}>>;
|
|
11
|
+
}
|
|
12
|
+
interface MessageResult {
|
|
13
|
+
sent: boolean;
|
|
14
|
+
channel: string;
|
|
15
|
+
messageId?: number;
|
|
16
|
+
error?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function message(params: MessageParams): Promise<MessageResult>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=message.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../src/tools/message.ts"],"names":[],"mappings":"AAEA,UAAU,aAAa;IACrB,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,YAAY,CAAC;IAC/C,cAAc,CAAC,EAAE,KAAK,CACpB,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAC7D,CAAC;CACH;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAoC3E"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { sendMessage } from "../lib/telegram.js";
|
|
2
|
+
export async function message(params) {
|
|
3
|
+
const botToken = process.env.TELEGRAM_PUBLIC_BOT_TOKEN;
|
|
4
|
+
if (!botToken) {
|
|
5
|
+
return {
|
|
6
|
+
sent: false,
|
|
7
|
+
channel: params.channel,
|
|
8
|
+
error: "TELEGRAM_PUBLIC_BOT_TOKEN not configured",
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
let replyMarkup;
|
|
12
|
+
if (params.inlineKeyboard) {
|
|
13
|
+
replyMarkup = {
|
|
14
|
+
inline_keyboard: params.inlineKeyboard.map((row) => row.map((btn) => ({
|
|
15
|
+
text: btn.text,
|
|
16
|
+
callback_data: btn.callbackData,
|
|
17
|
+
url: btn.url,
|
|
18
|
+
}))),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const result = await sendMessage(botToken, {
|
|
22
|
+
chatId: params.chatId,
|
|
23
|
+
text: params.text,
|
|
24
|
+
parseMode: params.parseMode,
|
|
25
|
+
replyMarkup,
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
sent: result.ok,
|
|
29
|
+
channel: "telegram",
|
|
30
|
+
messageId: result.messageId,
|
|
31
|
+
error: result.error,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=message.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../src/tools/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA+B,MAAM,oBAAoB,CAAC;AAmB9E,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,MAAqB;IACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;IACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,KAAK,EAAE,0CAA0C;SAClD,CAAC;IACJ,CAAC;IAED,IAAI,WAA+C,CAAC;IACpD,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;QAC1B,WAAW,GAAG;YACZ,eAAe,EAAE,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACjD,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAChB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,aAAa,EAAE,GAAG,CAAC,YAAY;gBAC/B,GAAG,EAAE,GAAG,CAAC,GAAG;aACb,CAAC,CAAC,CACJ;SACF,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE;QACzC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,WAAW;KACZ,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,EAAE;QACf,OAAO,EAAE,UAAU;QACnB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@maxy/messaging",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"start": "node dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
13
|
+
"neo4j-driver": "^5.28.1"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"typescript": "^5.7.0",
|
|
17
|
+
"@types/node": "^22.0.0"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Telegram Setup Guide
|
|
2
|
+
|
|
3
|
+
## Creating a Bot
|
|
4
|
+
|
|
5
|
+
1. Open Telegram and search for **@BotFather**
|
|
6
|
+
2. Start a chat and send `/newbot`
|
|
7
|
+
3. Follow the prompts — choose a display name and a username (must end in `bot`)
|
|
8
|
+
4. BotFather replies with a **bot token** (a long string like `123456:ABC-DEF...`)
|
|
9
|
+
5. Copy the token — you'll paste it into Taskmaster's Setup page
|
|
10
|
+
|
|
11
|
+
## Connecting the Bot to Taskmaster
|
|
12
|
+
|
|
13
|
+
1. Open the Taskmaster control panel (Setup page)
|
|
14
|
+
2. Find the **Telegram** row and click **Connect** (or open settings if already connected)
|
|
15
|
+
3. Paste the bot token from BotFather
|
|
16
|
+
4. The system probes the token to verify it — you'll see the bot's username confirmed
|
|
17
|
+
5. Choose whether this is an **admin bot** or a **public bot** (see below)
|
|
18
|
+
6. If it's a public bot, choose a DM policy (who can message it)
|
|
19
|
+
7. Click **Save & Connect**
|
|
20
|
+
|
|
21
|
+
## Admin Bot vs Public Bot
|
|
22
|
+
|
|
23
|
+
Each Telegram bot has an **Admin routing** toggle:
|
|
24
|
+
|
|
25
|
+
- **Admin bot** (toggle ON): Only users with admin bindings can message this bot. Everyone else is silently denied. Messages route to the admin agent. No DM policy applies — it's admin-only by design.
|
|
26
|
+
- **Public bot** (toggle OFF): DM policy applies to everyone equally, including admins. Messages route to the public agent. Use this for customer-facing bots.
|
|
27
|
+
|
|
28
|
+
A common setup is two bots: one admin bot for the business owner, one public bot for customers.
|
|
29
|
+
|
|
30
|
+
## Finding Your Telegram User ID
|
|
31
|
+
|
|
32
|
+
Admin bindings require your **numeric Telegram user ID** — not your username. Usernames can be changed or claimed by someone else, so they are not safe for admin access.
|
|
33
|
+
|
|
34
|
+
To find your user ID:
|
|
35
|
+
|
|
36
|
+
1. Open Telegram and search for **@userinfobot**
|
|
37
|
+
2. Start the chat and send `/start`
|
|
38
|
+
3. The bot instantly replies with your numeric ID (e.g. `123456789`), plus your name and language
|
|
39
|
+
4. Use this numeric ID when setting up admin bindings
|
|
40
|
+
|
|
41
|
+
## DM Policy Options (Public Bots Only)
|
|
42
|
+
|
|
43
|
+
| Policy | Behaviour |
|
|
44
|
+
|--------|-----------|
|
|
45
|
+
| **Respond to everyone** | Any Telegram user can message the bot and get a response |
|
|
46
|
+
| **Require approval** | Unknown senders receive a pairing code; an admin must approve them |
|
|
47
|
+
| **Whitelist only** | Only users in the allowlist can message the bot |
|
|
48
|
+
| **Disabled** | The bot ignores all DMs |
|
|
49
|
+
|
|
50
|
+
"Require approval" (pairing) is the default and recommended for most setups — it lets you control who talks to the bot without pre-configuring an allowlist.
|