@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.
Files changed (40) hide show
  1. package/dist/index.js +82 -37
  2. package/package.json +3 -3
  3. package/payload/maxy/package.json +1 -1
  4. package/payload/maxy/public/assets/{admin-h_MCGiva.js → admin-CvVTy3NI.js} +1 -1
  5. package/payload/maxy/public/brand/favicon.ico +0 -0
  6. package/payload/maxy/public/brand-constants.json +6 -6
  7. package/payload/maxy/public/brand-defaults.css +5 -5
  8. package/payload/maxy/public/index.html +2 -2
  9. package/payload/maxy/public/public.html +1 -1
  10. package/payload/maxy/server.js +29 -9
  11. package/payload/platform/config/brand.json +20 -22
  12. package/payload/platform/plugins/telegram/PLUGIN.md +34 -0
  13. package/payload/platform/plugins/telegram/mcp/dist/index.d.ts +2 -0
  14. package/payload/platform/plugins/telegram/mcp/dist/index.d.ts.map +1 -0
  15. package/payload/platform/plugins/telegram/mcp/dist/index.js +101 -0
  16. package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -0
  17. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.d.ts +27 -0
  18. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.d.ts.map +1 -0
  19. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.js +41 -0
  20. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.js.map +1 -0
  21. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.d.ts +16 -0
  22. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.d.ts.map +1 -0
  23. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js +62 -0
  24. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js.map +1 -0
  25. package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts +20 -0
  26. package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts.map +1 -0
  27. package/payload/platform/plugins/telegram/mcp/dist/tools/message.js +34 -0
  28. package/payload/platform/plugins/telegram/mcp/dist/tools/message.js.map +1 -0
  29. package/payload/platform/plugins/telegram/mcp/package.json +19 -0
  30. package/payload/platform/plugins/telegram/references/setup-guide.md +50 -0
  31. package/payload/platform/scripts/vnc.sh +20 -1
  32. package/payload/maxy/public/brand/demo-9pm-enquiry.svg +0 -95
  33. package/payload/maxy/public/brand/demo-create-agent.svg +0 -110
  34. package/payload/maxy/public/brand/demo-morning-briefing.svg +0 -83
  35. package/payload/maxy/public/brand/demo-post-viewing.svg +0 -107
  36. package/payload/maxy/public/brand/how-it-works.svg +0 -152
  37. package/payload/maxy/public/brand/realagent-favicon-dark-32.png +0 -0
  38. package/payload/maxy/public/brand/realagent-icon-dark-round-web.png +0 -0
  39. package/payload/maxy/public/brand/realagent-icon-dark-web.png +0 -0
  40. 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/realagent/brand.json */
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: #C5A572;
7
+ --visitor-bubble: #E8ECF0;
8
8
  --bg: #FAFAF8;
9
- --maxy-bubble: #F0EDE8;
10
- --font-display: 'Playfair Display', Georgia, serif;
11
- --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
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>Real Agent</title>
6
+ <title>Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/admin-h_MCGiva.js"></script>
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>Real Agent</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">
@@ -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 sleep(8e3);
9131
+ await waitForAuthPage(2e4);
9112
9132
  return Response.json({ started: true });
9113
9133
  }
9114
9134
 
@@ -1,45 +1,43 @@
1
1
  {
2
- "productName": "Real Agent",
3
- "hostname": "realagent",
4
- "serviceName": "realagent.service",
5
- "installDir": "realagent",
6
- "configDir": ".realagent",
7
- "tagline": "Built for agents. By agents.",
8
- "port": 19300,
9
- "domain": "realagency.network",
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": "#C5A572",
16
+ "accent": "#E8ECF0",
17
17
  "background": "#FAFAF8",
18
- "agentBubble": "#F0EDE8"
18
+ "agentBubble": "#F5F2ED"
19
19
  },
20
20
 
21
21
  "defaultFonts": {
22
- "display": "'Playfair Display', Georgia, serif",
23
- "body": "'Inter', -apple-system, BlinkMacSystemFont, sans-serif"
22
+ "display": "'Cormorant', Georgia, serif",
23
+ "body": "'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif"
24
24
  },
25
25
 
26
26
  "assets": {
27
- "logo": "realagent-icon-web.png",
28
- "logoMonochrome": "realagent-icon-web.png",
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-realagent",
35
- "binName": "create-realagent",
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", "business-assistant", "contacts", "scheduling"],
41
- "defaultEnabled": ["email", "sales"],
42
- "available": ["deep-research","waitlist", "projects"],
43
- "excluded": ["telegram"]
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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -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":"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"}
@@ -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.