@deadragdoll/tellymcp 0.0.1

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 (124) hide show
  1. package/.env.example.client +93 -0
  2. package/.env.example.gateway +120 -0
  3. package/CHANGELOG.md +155 -0
  4. package/LICENSE +21 -0
  5. package/README-ru.md +338 -0
  6. package/README.md +1262 -0
  7. package/STANDALONE-ru.md +266 -0
  8. package/STANDALONE.md +266 -0
  9. package/TOOLS.md +1296 -0
  10. package/config/templates/env.both.template +83 -0
  11. package/config/templates/env.client.template +60 -0
  12. package/config/templates/env.gateway.template +82 -0
  13. package/dist/cli.js +636 -0
  14. package/dist/index.js +17 -0
  15. package/dist/lib/logfeed/store.js +52 -0
  16. package/dist/lib/middlewares/tracer.js +172 -0
  17. package/dist/lib/mixins/db.js +267 -0
  18. package/dist/lib/mixins/logfeed.js +34 -0
  19. package/dist/lib/mixins/session.errors.js +142 -0
  20. package/dist/lib/moleculer.js +2 -0
  21. package/dist/lib/trace.js +147 -0
  22. package/dist/lib/traceContext.js +116 -0
  23. package/dist/moleculer.config.js +274 -0
  24. package/dist/services/features/telegram-mcp/approval.service.js +33 -0
  25. package/dist/services/features/telegram-mcp/browser.service.js +42 -0
  26. package/dist/services/features/telegram-mcp/collaboration.service.js +53 -0
  27. package/dist/services/features/telegram-mcp/ensuredb.service.js +337 -0
  28. package/dist/services/features/telegram-mcp/gateway-delivery.service.js +378 -0
  29. package/dist/services/features/telegram-mcp/gateway-loopback.js +10 -0
  30. package/dist/services/features/telegram-mcp/gateway-rmq.service.js +294 -0
  31. package/dist/services/features/telegram-mcp/gateway-socket.service.js +1463 -0
  32. package/dist/services/features/telegram-mcp/gateway.service.js +1141 -0
  33. package/dist/services/features/telegram-mcp/inbox.service.js +33 -0
  34. package/dist/services/features/telegram-mcp/mcp-http.service.js +76 -0
  35. package/dist/services/features/telegram-mcp/mcp-server.service.js +127 -0
  36. package/dist/services/features/telegram-mcp/notify.service.js +33 -0
  37. package/dist/services/features/telegram-mcp/pair.service.js +33 -0
  38. package/dist/services/features/telegram-mcp/runtime.service.js +36 -0
  39. package/dist/services/features/telegram-mcp/session-context.service.js +33 -0
  40. package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +103 -0
  41. package/dist/services/features/telegram-mcp/src/app/config/env.js +317 -0
  42. package/dist/services/features/telegram-mcp/src/app/http.js +774 -0
  43. package/dist/services/features/telegram-mcp/src/app/index.js +2 -0
  44. package/dist/services/features/telegram-mcp/src/app/providers/mcp/server.js +13 -0
  45. package/dist/services/features/telegram-mcp/src/app/providers/redis/client.js +18 -0
  46. package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +740 -0
  47. package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +267 -0
  48. package/dist/services/features/telegram-mcp/src/app/webapp/relay.js +69 -0
  49. package/dist/services/features/telegram-mcp/src/app/webapp/tmux.js +9 -0
  50. package/dist/services/features/telegram-mcp/src/entities/auth/model/types.js +2 -0
  51. package/dist/services/features/telegram-mcp/src/entities/browser/model/types.js +2 -0
  52. package/dist/services/features/telegram-mcp/src/entities/collaboration/model/types.js +2 -0
  53. package/dist/services/features/telegram-mcp/src/entities/inbox/model/types.js +2 -0
  54. package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +545 -0
  55. package/dist/services/features/telegram-mcp/src/entities/request/model/types.js +2 -0
  56. package/dist/services/features/telegram-mcp/src/entities/session/model/types.js +2 -0
  57. package/dist/services/features/telegram-mcp/src/features/ask-user/model/askUserTelegram.js +33 -0
  58. package/dist/services/features/telegram-mcp/src/features/browser/model/browserClearLogsTool.js +28 -0
  59. package/dist/services/features/telegram-mcp/src/features/browser/model/browserClickTool.js +28 -0
  60. package/dist/services/features/telegram-mcp/src/features/browser/model/browserCloseTool.js +28 -0
  61. package/dist/services/features/telegram-mcp/src/features/browser/model/browserComputedStyleTool.js +28 -0
  62. package/dist/services/features/telegram-mcp/src/features/browser/model/browserConsoleTool.js +28 -0
  63. package/dist/services/features/telegram-mcp/src/features/browser/model/browserDomTool.js +28 -0
  64. package/dist/services/features/telegram-mcp/src/features/browser/model/browserErrorsTool.js +28 -0
  65. package/dist/services/features/telegram-mcp/src/features/browser/model/browserFillTool.js +28 -0
  66. package/dist/services/features/telegram-mcp/src/features/browser/model/browserNetworkFailuresTool.js +28 -0
  67. package/dist/services/features/telegram-mcp/src/features/browser/model/browserOpenTool.js +33 -0
  68. package/dist/services/features/telegram-mcp/src/features/browser/model/browserPressTool.js +28 -0
  69. package/dist/services/features/telegram-mcp/src/features/browser/model/browserReloadTool.js +28 -0
  70. package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +28 -0
  71. package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +689 -0
  72. package/dist/services/features/telegram-mcp/src/features/browser/model/browserWaitForTool.js +28 -0
  73. package/dist/services/features/telegram-mcp/src/features/browser/model/browserWaitForUrlTool.js +28 -0
  74. package/dist/services/features/telegram-mcp/src/features/collaboration/model/backend.js +2 -0
  75. package/dist/services/features/telegram-mcp/src/features/collaboration/model/collaborationService.js +26 -0
  76. package/dist/services/features/telegram-mcp/src/features/collaboration/model/localCollaborationBackend.js +390 -0
  77. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +102 -0
  78. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileTool.js +33 -0
  79. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerNoteTool.js +33 -0
  80. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +69 -0
  81. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +657 -0
  82. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayReplyResolution.js +17 -0
  83. package/dist/services/features/telegram-mcp/src/features/inbox/model/deleteTelegramInboxMessageTool.js +33 -0
  84. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxCountTool.js +33 -0
  85. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxTool.js +33 -0
  86. package/dist/services/features/telegram-mcp/src/features/inbox/model/inboxService.js +77 -0
  87. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +93 -0
  88. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyTelegramTool.js +33 -0
  89. package/dist/services/features/telegram-mcp/src/features/pair-session/model/clearSessionPairingTool.js +33 -0
  90. package/dist/services/features/telegram-mcp/src/features/pair-session/model/createSessionPairCodeTool.js +33 -0
  91. package/dist/services/features/telegram-mcp/src/features/pair-session/model/generatePairCode.js +202 -0
  92. package/dist/services/features/telegram-mcp/src/features/session-context/model/clearSessionContextTool.js +33 -0
  93. package/dist/services/features/telegram-mcp/src/features/session-context/model/getSessionContextTool.js +33 -0
  94. package/dist/services/features/telegram-mcp/src/features/session-context/model/getTmuxTargetTool.js +33 -0
  95. package/dist/services/features/telegram-mcp/src/features/session-context/model/renameSessionTool.js +33 -0
  96. package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +409 -0
  97. package/dist/services/features/telegram-mcp/src/features/session-context/model/setSessionContextTool.js +33 -0
  98. package/dist/services/features/telegram-mcp/src/features/session-context/model/setTmuxTargetTool.js +33 -0
  99. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownService.js +123 -0
  100. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownTool.js +33 -0
  101. package/dist/services/features/telegram-mcp/src/processes/human-approval/model/orchestrator.js +243 -0
  102. package/dist/services/features/telegram-mcp/src/shared/api/storage/contract.js +2 -0
  103. package/dist/services/features/telegram-mcp/src/shared/api/tool-registry/registry.js +8 -0
  104. package/dist/services/features/telegram-mcp/src/shared/api/tool-registry/types.js +2 -0
  105. package/dist/services/features/telegram-mcp/src/shared/api/transport/contract.js +2 -0
  106. package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +86 -0
  107. package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +436 -0
  108. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/collabSemantics.js +21 -0
  109. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/collabUi.js +87 -0
  110. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/messageFormat.js +60 -0
  111. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/proxyFetch.js +46 -0
  112. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +6534 -0
  113. package/dist/services/features/telegram-mcp/src/shared/integrations/tmux/client.js +280 -0
  114. package/dist/services/features/telegram-mcp/src/shared/lib/ids/ids.js +34 -0
  115. package/dist/services/features/telegram-mcp/src/shared/lib/logger/logger.js +68 -0
  116. package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +223 -0
  117. package/dist/services/features/telegram-mcp/src/shared/lib/redact-secrets/redactSecrets.js +22 -0
  118. package/dist/services/features/telegram-mcp/src/shared/lib/truncate/truncate.js +12 -0
  119. package/dist/services/features/telegram-mcp/src/shared/lib/version/versionHandshake.js +124 -0
  120. package/dist/services/features/telegram-mcp/src/shared/types/common.js +2 -0
  121. package/dist/services/features/telegram-mcp/standalone-http.service.js +113 -0
  122. package/dist/services/features/telegram-mcp/tools-sync.service.js +33 -0
  123. package/package.json +110 -0
  124. package/scripts/postinstall.js +60 -0
@@ -0,0 +1,280 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ensureXchangeDir = ensureXchangeDir;
7
+ exports.writeXchangeFile = writeXchangeFile;
8
+ exports.writeXchangeRelativeFile = writeXchangeRelativeFile;
9
+ exports.listXchangeFiles = listXchangeFiles;
10
+ exports.deleteXchangeFile = deleteXchangeFile;
11
+ exports.readWorkspaceFile = readWorkspaceFile;
12
+ exports.isTmuxUnavailableError = isTmuxUnavailableError;
13
+ exports.getTmuxWindowHeight = getTmuxWindowHeight;
14
+ exports.captureTmuxPaneRange = captureTmuxPaneRange;
15
+ exports.captureVisibleTmuxPane = captureVisibleTmuxPane;
16
+ exports.sendAllowedTmuxAction = sendAllowedTmuxAction;
17
+ exports.sendTmuxLiteralLine = sendTmuxLiteralLine;
18
+ const node_child_process_1 = require("node:child_process");
19
+ const promises_1 = require("node:fs/promises");
20
+ const node_path_1 = __importDefault(require("node:path"));
21
+ const ENTER_AFTER_PASTE_DELAY_MS = 75;
22
+ const SUBMIT_LINE_KEY = "C-m";
23
+ function sanitizeFileName(fileName) {
24
+ const baseName = node_path_1.default.basename(fileName).trim();
25
+ const withoutControlChars = Array.from(baseName)
26
+ .map((char) => (char.charCodeAt(0) < 32 ? "-" : char))
27
+ .join("");
28
+ const normalized = withoutControlChars
29
+ .replace(/[/\\]/g, "-")
30
+ .replace(/[<>:"|?*]/g, "-")
31
+ .replace(/\s+/g, " ")
32
+ .trim();
33
+ return normalized || "file.bin";
34
+ }
35
+ function sanitizeRelativeXchangePath(relativePath) {
36
+ const normalized = relativePath
37
+ .split(/[/\\]+/u)
38
+ .map((segment) => segment.trim())
39
+ .filter((segment) => segment.length > 0 && segment !== "." && segment !== "..")
40
+ .join("/");
41
+ if (!normalized) {
42
+ throw new Error("Relative exchange path is required.");
43
+ }
44
+ return normalized;
45
+ }
46
+ function resolvePathInsideRoot(rootDir, relativePath) {
47
+ const safeRelativePath = sanitizeRelativeXchangePath(relativePath);
48
+ const resolvedPath = node_path_1.default.resolve(rootDir, safeRelativePath);
49
+ const relative = node_path_1.default.relative(rootDir, resolvedPath);
50
+ if (relative.startsWith("..") ||
51
+ node_path_1.default.isAbsolute(relative) ||
52
+ relative.trim() === "") {
53
+ throw new Error("Resolved path is outside the exchange directory.");
54
+ }
55
+ return resolvedPath;
56
+ }
57
+ function resolvePathInsideWorkspace(workspaceDir, filePath) {
58
+ const resolvedWorkspaceDir = node_path_1.default.resolve(workspaceDir);
59
+ const resolvedFilePath = node_path_1.default.isAbsolute(filePath)
60
+ ? node_path_1.default.resolve(filePath)
61
+ : node_path_1.default.resolve(resolvedWorkspaceDir, filePath);
62
+ const relative = node_path_1.default.relative(resolvedWorkspaceDir, resolvedFilePath);
63
+ if (relative.startsWith("..") ||
64
+ node_path_1.default.isAbsolute(relative) ||
65
+ relative.trim() === "") {
66
+ throw new Error("File path is outside the workspace directory.");
67
+ }
68
+ return resolvedFilePath;
69
+ }
70
+ async function allocateAvailableFilePath(dir, fileName) {
71
+ const safeFileName = sanitizeFileName(fileName);
72
+ const extension = node_path_1.default.extname(safeFileName);
73
+ const baseName = node_path_1.default.basename(safeFileName, extension);
74
+ for (let attempt = 0; attempt < 1000; attempt += 1) {
75
+ const candidateName = attempt === 0
76
+ ? safeFileName
77
+ : `${baseName}--${attempt}${extension}`;
78
+ const candidatePath = node_path_1.default.join(dir, candidateName);
79
+ try {
80
+ await (0, promises_1.access)(candidatePath);
81
+ }
82
+ catch {
83
+ return candidatePath;
84
+ }
85
+ }
86
+ throw new Error("Could not allocate a unique file name in exchange directory.");
87
+ }
88
+ function delay(ms) {
89
+ return new Promise((resolve) => {
90
+ setTimeout(resolve, ms);
91
+ });
92
+ }
93
+ function execFileAsync(command, args) {
94
+ return new Promise((resolve, reject) => {
95
+ (0, node_child_process_1.execFile)(command, args, (error) => {
96
+ if (error) {
97
+ reject(error);
98
+ return;
99
+ }
100
+ resolve();
101
+ });
102
+ });
103
+ }
104
+ function execFileOutputAsync(command, args) {
105
+ return new Promise((resolve, reject) => {
106
+ (0, node_child_process_1.execFile)(command, args, (error, stdout, stderr) => {
107
+ if (error) {
108
+ reject(error);
109
+ return;
110
+ }
111
+ resolve({ stdout, stderr });
112
+ });
113
+ });
114
+ }
115
+ function buildTmuxArgs(config, args, socketPath) {
116
+ const resolvedSocketPath = socketPath ?? config.socketPath;
117
+ return resolvedSocketPath ? ["-S", resolvedSocketPath, ...args] : args;
118
+ }
119
+ async function ensureXchangeDir(config, workspaceDir, exchangeDirName) {
120
+ const resolvedDir = node_path_1.default.resolve(workspaceDir, exchangeDirName);
121
+ await (0, promises_1.mkdir)(resolvedDir, { recursive: true });
122
+ return resolvedDir;
123
+ }
124
+ async function writeXchangeFile(config, workspaceDir, exchangeDirName, fileName, content) {
125
+ const dir = await ensureXchangeDir(config, workspaceDir, exchangeDirName);
126
+ const outputPath = await allocateAvailableFilePath(dir, fileName);
127
+ await (0, promises_1.writeFile)(outputPath, content);
128
+ return outputPath;
129
+ }
130
+ async function writeXchangeRelativeFile(config, workspaceDir, exchangeDirName, relativePath, content, options) {
131
+ const dir = await ensureXchangeDir(config, workspaceDir, exchangeDirName);
132
+ const outputPath = resolvePathInsideRoot(dir, relativePath);
133
+ await (0, promises_1.mkdir)(node_path_1.default.dirname(outputPath), { recursive: true });
134
+ if (options?.append) {
135
+ await (0, promises_1.appendFile)(outputPath, content);
136
+ }
137
+ else {
138
+ await (0, promises_1.writeFile)(outputPath, content);
139
+ }
140
+ return outputPath;
141
+ }
142
+ async function listXchangeFiles(config, workspaceDir, exchangeDirName) {
143
+ const dir = await ensureXchangeDir(config, workspaceDir, exchangeDirName);
144
+ return listFilesRecursively(dir);
145
+ }
146
+ async function listFilesRecursively(rootDir) {
147
+ const files = [];
148
+ const stack = [rootDir];
149
+ while (stack.length > 0) {
150
+ const currentDir = stack.pop();
151
+ if (!currentDir) {
152
+ continue;
153
+ }
154
+ const entries = await (0, promises_1.readdir)(currentDir, { withFileTypes: true });
155
+ for (const entry of entries) {
156
+ const fullPath = node_path_1.default.join(currentDir, entry.name);
157
+ if (entry.isDirectory()) {
158
+ stack.push(fullPath);
159
+ continue;
160
+ }
161
+ if (entry.isFile()) {
162
+ files.push(fullPath);
163
+ }
164
+ }
165
+ }
166
+ return files.sort((left, right) => right.localeCompare(left));
167
+ }
168
+ async function deleteXchangeFile(config, workspaceDir, exchangeDirName, filePath) {
169
+ const dir = await ensureXchangeDir(config, workspaceDir, exchangeDirName);
170
+ const resolvedFilePath = node_path_1.default.resolve(filePath);
171
+ const relative = node_path_1.default.relative(dir, resolvedFilePath);
172
+ if (relative.startsWith("..") ||
173
+ node_path_1.default.isAbsolute(relative) ||
174
+ relative.trim() === "") {
175
+ throw new Error("File path is outside the exchange directory.");
176
+ }
177
+ await (0, promises_1.rm)(resolvedFilePath, { force: true });
178
+ return true;
179
+ }
180
+ async function readWorkspaceFile(config, workspaceDir, filePath) {
181
+ const resolvedFilePath = resolvePathInsideWorkspace(workspaceDir, filePath);
182
+ return (0, promises_1.readFile)(resolvedFilePath);
183
+ }
184
+ function isTmuxUnavailableError(error) {
185
+ const message = error instanceof Error ? (error.stack ?? error.message) : String(error);
186
+ return (message.includes("error connecting to /tmp/tmux-") ||
187
+ message.includes("No such file or directory") ||
188
+ message.includes("ENOENT") ||
189
+ message.includes("tmux is unavailable"));
190
+ }
191
+ async function getTmuxWindowHeight(config, target) {
192
+ const { stdout: heightRaw } = await execFileOutputAsync("tmux", buildTmuxArgs(config, ["display-message", "-p", "-t", target, "#{window_height}"]));
193
+ const height = Number.parseInt(heightRaw.trim(), 10);
194
+ return Number.isFinite(height) && height > 0 ? height : null;
195
+ }
196
+ async function captureTmuxPaneRange(config, target, start, includeEscapes) {
197
+ const args = [
198
+ "capture-pane",
199
+ "-p",
200
+ ...(includeEscapes ? ["-e"] : []),
201
+ "-t",
202
+ target,
203
+ "-S",
204
+ start,
205
+ ];
206
+ const { stdout } = await execFileOutputAsync("tmux", buildTmuxArgs(config, args));
207
+ return stdout.replaceAll("\u0000", "");
208
+ }
209
+ async function captureVisibleTmuxPane(config, target, fallbackLines, visibleScreens) {
210
+ const height = await getTmuxWindowHeight(config, target);
211
+ const baseLines = typeof height === "number" && height > 0 ? height : Math.max(1, fallbackLines);
212
+ const lines = Math.max(1, baseLines * Math.max(1, visibleScreens));
213
+ let stdout = "";
214
+ try {
215
+ ({ stdout } = await execFileOutputAsync("tmux", buildTmuxArgs(config, [
216
+ "capture-pane",
217
+ "-p",
218
+ "-e",
219
+ "-a",
220
+ "-t",
221
+ target,
222
+ "-S",
223
+ `-${lines}`,
224
+ ])));
225
+ }
226
+ catch (error) {
227
+ const message = error instanceof Error ? (error.stack ?? error.message) : String(error);
228
+ if (!message.includes("no alternate screen")) {
229
+ throw error;
230
+ }
231
+ ({ stdout } = await execFileOutputAsync("tmux", buildTmuxArgs(config, [
232
+ "capture-pane",
233
+ "-p",
234
+ "-e",
235
+ "-t",
236
+ target,
237
+ "-S",
238
+ `-${lines}`,
239
+ ])));
240
+ }
241
+ return stdout.replaceAll("\u0000", "");
242
+ }
243
+ async function sendAllowedTmuxAction(config, target, action) {
244
+ const key = action === "up"
245
+ ? "Up"
246
+ : action === "down"
247
+ ? "Down"
248
+ : action === "slash"
249
+ ? "/"
250
+ : action === "delete"
251
+ ? "BSpace"
252
+ : action === "tab"
253
+ ? "Tab"
254
+ : action === "escape"
255
+ ? "Escape"
256
+ : "Enter";
257
+ await execFileAsync("tmux", buildTmuxArgs(config, ["send-keys", "-t", target, key]));
258
+ }
259
+ async function sendTmuxLiteralLine(config, target, text) {
260
+ const normalized = text.replace(/\r?\n/g, " ").trim();
261
+ const bufferName = `telegram-mcp-${Date.now().toString(36)}`;
262
+ if (normalized.length > 0) {
263
+ try {
264
+ await execFileAsync("tmux", buildTmuxArgs(config, ["set-buffer", "-b", bufferName, normalized]));
265
+ await execFileAsync("tmux", buildTmuxArgs(config, [
266
+ "paste-buffer",
267
+ "-d",
268
+ "-b",
269
+ bufferName,
270
+ "-t",
271
+ target,
272
+ ]));
273
+ }
274
+ finally {
275
+ await execFileAsync("tmux", buildTmuxArgs(config, ["delete-buffer", "-b", bufferName])).catch(() => undefined);
276
+ }
277
+ await delay(ENTER_AFTER_PASTE_DELAY_MS);
278
+ }
279
+ await execFileAsync("tmux", buildTmuxArgs(config, ["send-keys", "-t", target, SUBMIT_LINE_KEY]));
280
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createRequestId = createRequestId;
4
+ exports.createPairCode = createPairCode;
5
+ exports.createInboxMessageId = createInboxMessageId;
6
+ exports.createMenuPayloadKey = createMenuPayloadKey;
7
+ const node_crypto_1 = require("node:crypto");
8
+ function randomBase36(size) {
9
+ return (0, node_crypto_1.randomBytes)(size)
10
+ .toString("base64url")
11
+ .replace(/[^A-Za-z0-9]/g, "")
12
+ .slice(0, size)
13
+ .toUpperCase();
14
+ }
15
+ function createRequestId(now = new Date()) {
16
+ const timestamp = now
17
+ .toISOString()
18
+ .replace(/[-:.TZ]/g, "")
19
+ .slice(0, 14);
20
+ return `req_${timestamp}_${randomBase36(6).toLowerCase()}`;
21
+ }
22
+ function createPairCode() {
23
+ return (0, node_crypto_1.randomInt)(0, 1000).toString().padStart(3, "0");
24
+ }
25
+ function createInboxMessageId(now = new Date()) {
26
+ const timestamp = now
27
+ .toISOString()
28
+ .replace(/[-:.TZ]/g, "")
29
+ .slice(0, 14);
30
+ return `inbox_${timestamp}_${randomBase36(6).toLowerCase()}`;
31
+ }
32
+ function createMenuPayloadKey() {
33
+ return `mk_${randomBase36(8).toLowerCase()}`;
34
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createLogger = createLogger;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = require("node:path");
9
+ const pino_1 = __importDefault(require("pino"));
10
+ const DEFAULT_LOG_FILE_PATH = ".telegram-human-mcp/log.jsonl";
11
+ function write(logger, level, message, meta) {
12
+ if (meta) {
13
+ logger[level](meta, message);
14
+ return;
15
+ }
16
+ logger[level](message);
17
+ }
18
+ function createLogger(config) {
19
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(DEFAULT_LOG_FILE_PATH), { recursive: true });
20
+ const transport = pino_1.default.transport({
21
+ targets: [
22
+ {
23
+ target: "pino/file",
24
+ level: config.logging.level,
25
+ options: {
26
+ destination: DEFAULT_LOG_FILE_PATH,
27
+ mkdir: true,
28
+ },
29
+ },
30
+ {
31
+ target: "pino-pretty",
32
+ level: config.logging.level,
33
+ options: {
34
+ destination: 2,
35
+ colorize: true,
36
+ translateTime: "SYS:standard",
37
+ ignore: "pid,hostname",
38
+ singleLine: false,
39
+ },
40
+ },
41
+ ],
42
+ });
43
+ const baseLogger = (0, pino_1.default)({
44
+ name: "telegram-human-mcp",
45
+ level: config.logging.level,
46
+ timestamp: pino_1.default.stdTimeFunctions.isoTime,
47
+ }, transport);
48
+ return {
49
+ trace(message, meta) {
50
+ write(baseLogger, "trace", message, meta);
51
+ },
52
+ debug(message, meta) {
53
+ write(baseLogger, "debug", message, meta);
54
+ },
55
+ info(message, meta) {
56
+ write(baseLogger, "info", message, meta);
57
+ },
58
+ warn(message, meta) {
59
+ write(baseLogger, "warn", message, meta);
60
+ },
61
+ error(message, meta) {
62
+ write(baseLogger, "error", message, meta);
63
+ },
64
+ fatal(message, meta) {
65
+ write(baseLogger, "fatal", message, meta);
66
+ },
67
+ };
68
+ }
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProjectIdentityResolver = void 0;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ const SESSION_MARKER_FILE_NAME = ".mcpsession.json";
8
+ function slugify(input) {
9
+ return input
10
+ .trim()
11
+ .toLowerCase()
12
+ .replace(/[^a-z0-9]+/g, "-")
13
+ .replace(/^-+|-+$/g, "")
14
+ .replace(/-{2,}/g, "-");
15
+ }
16
+ function shortHash(input) {
17
+ return (0, node_crypto_1.createHash)("sha1").update(input).digest("hex").slice(0, 8);
18
+ }
19
+ function findUpward(startDir, target) {
20
+ let current = (0, node_path_1.resolve)(startDir);
21
+ while (true) {
22
+ const candidate = (0, node_path_1.join)(current, target);
23
+ if ((0, node_fs_1.existsSync)(candidate)) {
24
+ return candidate;
25
+ }
26
+ const parent = (0, node_path_1.dirname)(current);
27
+ if (parent === current) {
28
+ return undefined;
29
+ }
30
+ current = parent;
31
+ }
32
+ }
33
+ function readPackageName(packageJsonPath) {
34
+ if (!packageJsonPath) {
35
+ return undefined;
36
+ }
37
+ try {
38
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, "utf8"));
39
+ return typeof parsed.name === "string" && parsed.name.trim()
40
+ ? parsed.name.trim()
41
+ : undefined;
42
+ }
43
+ catch {
44
+ return undefined;
45
+ }
46
+ }
47
+ function normalizeOptionalString(value) {
48
+ const trimmed = value?.trim();
49
+ return trimmed ? trimmed : undefined;
50
+ }
51
+ function resolveInputCwd(value) {
52
+ const trimmed = normalizeOptionalString(value);
53
+ return trimmed ? (0, node_path_1.resolve)(trimmed) : undefined;
54
+ }
55
+ class ProjectIdentityResolver {
56
+ config;
57
+ logger;
58
+ identity;
59
+ constructor(config, logger) {
60
+ this.config = config;
61
+ this.logger = logger;
62
+ this.identity = this.buildIdentity();
63
+ this.logger.info("Project identity resolved", {
64
+ cwd: this.identity.cwd,
65
+ cwdName: this.identity.cwdName,
66
+ gitRoot: this.identity.gitRoot,
67
+ gitRootName: this.identity.gitRootName,
68
+ packageName: this.identity.packageName,
69
+ configuredProjectName: this.identity.configuredProjectName,
70
+ resolvedTitle: this.identity.resolvedTitle,
71
+ resolvedSessionId: this.identity.resolvedSessionId,
72
+ titleSource: this.identity.titleSource,
73
+ });
74
+ }
75
+ getIdentity() {
76
+ return this.identity;
77
+ }
78
+ resolveSessionDefaults(input) {
79
+ const inputCwd = resolveInputCwd(input.cwd);
80
+ const resolvedCwd = inputCwd || this.identity.cwd;
81
+ const titleBase = (0, node_path_1.basename)(resolvedCwd) || this.identity.resolvedTitle || "Project";
82
+ const sessionMarker = this.readSessionMarker(resolvedCwd);
83
+ const derivedSessionId = sessionMarker?.localSessionId ||
84
+ `${slugify(titleBase) || "session"}-${shortHash(resolvedCwd)}`;
85
+ const derivedSessionLabel = sessionMarker?.sessionLabel || titleBase;
86
+ const explicitSessionId = input.session_id?.trim();
87
+ const explicitSessionLabel = input.session_label?.trim();
88
+ if (!sessionMarker) {
89
+ this.writeSessionMarker(resolvedCwd, {
90
+ localSessionId: explicitSessionId || derivedSessionId,
91
+ sessionLabel: explicitSessionLabel || derivedSessionLabel,
92
+ cwd: resolvedCwd,
93
+ });
94
+ }
95
+ return {
96
+ sessionId: explicitSessionId || derivedSessionId,
97
+ sessionLabel: explicitSessionLabel || derivedSessionLabel,
98
+ cwd: resolvedCwd,
99
+ sessionIdDerived: !explicitSessionId,
100
+ sessionLabelDerived: !explicitSessionLabel,
101
+ };
102
+ }
103
+ persistSessionMarker(input) {
104
+ const resolvedCwd = resolveInputCwd(input.cwd) || this.identity.cwd;
105
+ const current = this.readSessionMarker(resolvedCwd);
106
+ this.writeSessionMarker(resolvedCwd, {
107
+ localSessionId: input.sessionId,
108
+ sessionLabel: input.sessionLabel || current?.sessionLabel,
109
+ cwd: resolvedCwd,
110
+ });
111
+ }
112
+ removeSessionMarker(cwd) {
113
+ const resolvedCwd = resolveInputCwd(cwd) || this.identity.cwd;
114
+ const markerPath = (0, node_path_1.join)(resolvedCwd, SESSION_MARKER_FILE_NAME);
115
+ if (!(0, node_fs_1.existsSync)(markerPath)) {
116
+ return;
117
+ }
118
+ try {
119
+ (0, node_fs_1.rmSync)(markerPath, { force: true });
120
+ }
121
+ catch (error) {
122
+ this.logger.warn("Failed to remove .mcpsession.json", {
123
+ cwd: resolvedCwd,
124
+ markerPath,
125
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
126
+ });
127
+ }
128
+ }
129
+ buildIdentity() {
130
+ const cwd = process.cwd();
131
+ const cwdName = (0, node_path_1.basename)(cwd);
132
+ const gitMarkerPath = findUpward(cwd, ".git");
133
+ const gitRoot = gitMarkerPath ? (0, node_path_1.dirname)(gitMarkerPath) : undefined;
134
+ const gitRootName = gitRoot ? (0, node_path_1.basename)(gitRoot) : undefined;
135
+ const packageJsonPath = findUpward(cwd, "package.json");
136
+ const packageName = readPackageName(packageJsonPath);
137
+ const configuredProjectName = this.config.project.name;
138
+ const titleCandidate = configuredProjectName || packageName || gitRootName || cwdName;
139
+ const titleSource = configuredProjectName
140
+ ? "env"
141
+ : packageName
142
+ ? "package.json"
143
+ : gitRootName
144
+ ? "git"
145
+ : cwdName
146
+ ? "cwd"
147
+ : "generated";
148
+ const resolvedTitle = titleCandidate || "Project";
149
+ const slugBase = slugify(resolvedTitle) || "session";
150
+ const fingerprint = shortHash(gitRoot || packageJsonPath || cwd);
151
+ const resolvedSessionId = `${slugBase}-${fingerprint}`.slice(0, 64);
152
+ return {
153
+ cwd,
154
+ cwdName,
155
+ ...(gitRoot ? { gitRoot } : {}),
156
+ ...(gitRootName ? { gitRootName } : {}),
157
+ ...(packageJsonPath ? { packageJsonPath } : {}),
158
+ ...(packageName ? { packageName } : {}),
159
+ ...(configuredProjectName ? { configuredProjectName } : {}),
160
+ resolvedTitle,
161
+ resolvedSessionId,
162
+ titleSource,
163
+ };
164
+ }
165
+ readSessionMarker(cwd) {
166
+ const markerPath = (0, node_path_1.join)(cwd, SESSION_MARKER_FILE_NAME);
167
+ if (!(0, node_fs_1.existsSync)(markerPath)) {
168
+ return null;
169
+ }
170
+ try {
171
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)(markerPath, "utf8"));
172
+ const localSessionId = typeof parsed.local_session_id === "string"
173
+ ? parsed.local_session_id.trim()
174
+ : "";
175
+ if (!localSessionId) {
176
+ return null;
177
+ }
178
+ return {
179
+ localSessionId,
180
+ ...(typeof parsed.session_label === "string" &&
181
+ parsed.session_label.trim()
182
+ ? { sessionLabel: parsed.session_label.trim() }
183
+ : {}),
184
+ ...(typeof parsed.cwd === "string" && parsed.cwd.trim()
185
+ ? { cwd: parsed.cwd.trim() }
186
+ : {}),
187
+ };
188
+ }
189
+ catch (error) {
190
+ this.logger.warn("Failed to read .mcpsession.json, ignoring marker", {
191
+ cwd,
192
+ markerPath,
193
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
194
+ });
195
+ return null;
196
+ }
197
+ }
198
+ writeSessionMarker(inputCwd, input) {
199
+ const markerPath = (0, node_path_1.join)(inputCwd, SESSION_MARKER_FILE_NAME);
200
+ const now = new Date().toISOString();
201
+ const current = this.readSessionMarker(inputCwd);
202
+ try {
203
+ (0, node_fs_1.writeFileSync)(markerPath, `${JSON.stringify({
204
+ version: 1,
205
+ local_session_id: input.localSessionId,
206
+ ...(input.sessionLabel ? { session_label: input.sessionLabel } : {}),
207
+ cwd: input.cwd,
208
+ created_at: now,
209
+ updated_at: now,
210
+ ...(current ? { first_seen_local_session_id: current.localSessionId } : {}),
211
+ }, null, 2)}\n`, "utf8");
212
+ }
213
+ catch (error) {
214
+ this.logger.warn("Failed to write .mcpsession.json", {
215
+ cwd: inputCwd,
216
+ markerPath,
217
+ sessionId: input.localSessionId,
218
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
219
+ });
220
+ }
221
+ }
222
+ }
223
+ exports.ProjectIdentityResolver = ProjectIdentityResolver;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.redactSecrets = redactSecrets;
4
+ const SECRET_PATTERNS = [
5
+ [/sk-[A-Za-z0-9]{20,}/g, "[REDACTED_OPENAI_KEY]"],
6
+ [/\bgh[pousr]_[A-Za-z0-9]{20,}\b/g, "[REDACTED_GITHUB_TOKEN]"],
7
+ [/\bBearer\s+[A-Za-z0-9._\-+/=]+\b/gi, "Bearer [REDACTED]"],
8
+ [/\bpostgres(?:ql)?:\/\/[^\s]+/gi, "postgres://[REDACTED]"],
9
+ [/\bDATABASE_URL\s*=\s*[^\s]+/gi, "DATABASE_URL=[REDACTED]"],
10
+ [
11
+ /-----BEGIN [A-Z ]+PRIVATE KEY-----[\s\S]*?-----END [A-Z ]+PRIVATE KEY-----/g,
12
+ "[REDACTED_PRIVATE_KEY]",
13
+ ],
14
+ [/\b(?:password|passwd|pwd)\s*[:=]\s*[^\s'"]+/gi, "password=[REDACTED]"],
15
+ [/\bapi[_-]?key\s*[:=]\s*[^\s'"]+/gi, "api_key=[REDACTED]"],
16
+ [/\bsecret\s*[:=]\s*[^\s'"]+/gi, "secret=[REDACTED]"],
17
+ [/\btoken\s*[:=]\s*[^\s'"]+/gi, "token=[REDACTED]"],
18
+ [/\b[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\b/g, "[REDACTED_JWT]"],
19
+ ];
20
+ function redactSecrets(input) {
21
+ return SECRET_PATTERNS.reduce((current, [pattern, replacement]) => current.replace(pattern, replacement), input);
22
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.truncateText = truncateText;
4
+ function truncateText(input, maxChars, suffix = " [truncated]") {
5
+ if (input.length <= maxChars) {
6
+ return input;
7
+ }
8
+ if (maxChars <= suffix.length) {
9
+ return input.slice(0, maxChars);
10
+ }
11
+ return `${input.slice(0, maxChars - suffix.length)}${suffix}`;
12
+ }