@deadragdoll/tellymcp 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README-ru.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TellyMCP
2
2
 
3
- [English](README.md) | [Русский](README-ru.md) | [Standalone Guide](STANDALONE.md) | [Standalone RU](STANDALONE-ru.md)
3
+ [English](README.md) | [Русский](README-ru.md) | [Standalone Guide](STANDALONE.md) | [Standalone RU](STANDALONE-ru.md) | [Release Notes](VERSION.md)
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/%40deadragdoll%2Ftellymcp)](https://www.npmjs.com/package/@deadragdoll/tellymcp)
6
6
  [![npm downloads](https://img.shields.io/npm/dm/%40deadragdoll%2Ftellymcp)](https://www.npmjs.com/package/@deadragdoll/tellymcp)
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TellyMCP
2
2
 
3
- [English](README.md) | [Русский](README-ru.md) | [Standalone Guide](STANDALONE.md) | [Standalone RU](STANDALONE-ru.md)
3
+ [English](README.md) | [Русский](README-ru.md) | [Standalone Guide](STANDALONE.md) | [Standalone RU](STANDALONE-ru.md) | [Release Notes](VERSION.md)
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/%40deadragdoll%2Ftellymcp)](https://www.npmjs.com/package/@deadragdoll/tellymcp)
6
6
  [![npm downloads](https://img.shields.io/npm/dm/%40deadragdoll%2Ftellymcp)](https://www.npmjs.com/package/@deadragdoll/tellymcp)
package/VERSION.md ADDED
@@ -0,0 +1,93 @@
1
+ # TellyMCP Release Notes
2
+
3
+ Public, user-facing release notes for published versions of `@deadragdoll/tellymcp`.
4
+
5
+ For detailed engineering history, refactors, and internal development notes, see [CHANGELOG.md](CHANGELOG.md).
6
+
7
+ ## 0.0.3
8
+
9
+ ### Added
10
+ - Standalone CLI workflow:
11
+ - `tellymcp init <client|gateway|both>`
12
+ - `tellymcp run`
13
+ - `tellymcp doctor`
14
+ - `tellymcp mcp --help`
15
+ - Standalone and public installation guides:
16
+ - [STANDALONE.md](STANDALONE.md)
17
+ - [STANDALONE-ru.md](STANDALONE-ru.md)
18
+ - Browser runtime helper:
19
+ - `tellymcp browser install`
20
+ - Public README set for GitHub and npm:
21
+ - [README.md](README.md)
22
+ - [README-ru.md](README-ru.md)
23
+ - Human-readable release notes in this file.
24
+
25
+ ### Changed
26
+ - Default installation path is now npm-first:
27
+ - `npm install -g @deadragdoll/tellymcp`
28
+ - Standalone client mode is documented first, before gateway/both deployment.
29
+ - `tmux` is now documented as a strongly recommended prerequisite for the full experience:
30
+ - Live View
31
+ - nudges
32
+ - direct terminal control from Telegram
33
+ - Environment examples were split into dedicated client and gateway variants.
34
+ - Package build/publish flow now validates itself before packing/publishing.
35
+
36
+ ### Collaboration
37
+ - Project collaboration works across local and remote sessions.
38
+ - `Collab` now includes:
39
+ - `Broadcast`
40
+ - `History`
41
+ - `Delete`
42
+ - `Ask` and `Share` semantics were clarified:
43
+ - `Ask` tells the selected session to do the work and reply back
44
+ - `Share` tells the current session to send something to the selected session
45
+
46
+ ### Live View
47
+ - Telegram Mini App Live View supports:
48
+ - fullscreen/expand launch policy
49
+ - bottom toolbar layout
50
+ - `Esc`
51
+ - `Tab`
52
+ - `Ctrl+C`
53
+ - `Backspace`
54
+ - `Up`
55
+ - `Down`
56
+ - `Enter`
57
+ - Live approval flow was added for remote project sessions.
58
+
59
+ ### Browser
60
+ - Browser tools use Playwright Chromium.
61
+ - Headless mode is the recommended default for remote and SSH-based environments.
62
+ - `doctor` now helps detect missing browser runtime and connectivity issues.
63
+
64
+ ### Compatibility
65
+ - Gateway and clients now compare:
66
+ - package version
67
+ - protocol version
68
+ - capabilities
69
+ - `TOOLS.md` sync now detects outdated or missing local instructions and asks the session to refresh them.
70
+
71
+ ### Removed
72
+ - Legacy Go/HTTP tmux proxy path was removed.
73
+ - Direct product path is now local `tmux` only.
74
+
75
+ ## Next entry template
76
+
77
+ Copy this block for the next published version:
78
+
79
+ ```md
80
+ ## x.y.z
81
+
82
+ ### Added
83
+ - ...
84
+
85
+ ### Changed
86
+ - ...
87
+
88
+ ### Fixed
89
+ - ...
90
+
91
+ ### Removed
92
+ - ...
93
+ ```
package/dist/cli.js CHANGED
@@ -11,8 +11,10 @@ const node_net_1 = __importDefault(require("node:net"));
11
11
  const dotenv_1 = require("dotenv");
12
12
  const picocolors_1 = __importDefault(require("picocolors"));
13
13
  const ws_1 = __importDefault(require("ws"));
14
+ const versionHandshake_1 = require("./services/features/telegram-mcp/src/shared/lib/version/versionHandshake");
14
15
  const distDir = __dirname;
15
16
  const packageRoot = node_path_1.default.resolve(distDir, "..");
17
+ const cliPackageVersion = (0, versionHandshake_1.getTellyMcpPackageVersion)(__dirname);
16
18
  function getTmuxStatus() {
17
19
  const result = (0, node_child_process_1.spawnSync)("tmux", ["-V"], {
18
20
  encoding: "utf8",
@@ -27,7 +29,7 @@ function getTmuxStatus() {
27
29
  return { found: false };
28
30
  }
29
31
  function printBanner(title, subtitle) {
30
- process.stdout.write(`${picocolors_1.default.bold(picocolors_1.default.cyan("TellyMCP"))} ${picocolors_1.default.dim(title)}\n`);
32
+ process.stdout.write(`${picocolors_1.default.bold(picocolors_1.default.cyan("TellyMCP"))} ${picocolors_1.default.bold(picocolors_1.default.white(`v${cliPackageVersion}`))} ${picocolors_1.default.dim(title)}\n`);
31
33
  if (subtitle) {
32
34
  process.stdout.write(`${picocolors_1.default.dim(subtitle)}\n`);
33
35
  }
@@ -666,6 +668,7 @@ function runRuntime(args) {
666
668
  if (!(0, node_fs_1.existsSync)(servicesPath)) {
667
669
  fail(`Missing compiled services: ${servicesPath}`);
668
670
  }
671
+ printBanner("run", "Starting packaged runtime");
669
672
  const tmux = getTmuxStatus();
670
673
  if (tmux.found) {
671
674
  process.stdout.write(`${picocolors_1.default.green("tmux detected:")} ${tmux.version}\n`);
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TELEGRAM_MCP_RUNTIME_SERVICE_NAME = void 0;
4
4
  const runtime_1 = require("./src/app/bootstrap/runtime");
5
+ const versionHandshake_1 = require("./src/shared/lib/version/versionHandshake");
5
6
  exports.TELEGRAM_MCP_RUNTIME_SERVICE_NAME = "telegramMcp.runtime";
6
7
  const TelegramMcpRuntimeService = {
7
8
  name: exports.TELEGRAM_MCP_RUNTIME_SERVICE_NAME,
@@ -17,11 +18,17 @@ const TelegramMcpRuntimeService = {
17
18
  },
18
19
  },
19
20
  async started() {
20
- this.logger.info("Starting telegram_mcp runtime service");
21
+ this.logger.info("Starting telegram_mcp runtime service", {
22
+ packageVersion: (0, versionHandshake_1.getTellyMcpPackageVersion)(__dirname),
23
+ protocolVersion: versionHandshake_1.TELLYMCP_PROTOCOL_VERSION,
24
+ });
21
25
  this.runtime = await (0, runtime_1.createAppRuntime)({
22
26
  callBroker: (actionName, params, options) => this.broker.call(actionName, params, options),
23
27
  });
24
- this.logger.info("telegram_mcp runtime service is ready");
28
+ this.logger.info("telegram_mcp runtime service is ready", {
29
+ packageVersion: (0, versionHandshake_1.getTellyMcpPackageVersion)(__dirname),
30
+ protocolVersion: versionHandshake_1.TELLYMCP_PROTOCOL_VERSION,
31
+ });
25
32
  },
26
33
  async stopped() {
27
34
  if (!this.runtime) {
@@ -77,6 +77,8 @@ async function createAppRuntime(input) {
77
77
  logger.info("Telegram transport ready");
78
78
  await telegramTransport.recoverPendingInboxNudges();
79
79
  logger.info("Startup inbox nudge recovery completed");
80
+ await telegramTransport.sendStartupNotifications();
81
+ logger.info("Startup Telegram notifications completed");
80
82
  const gatewayHttpService = new gatewayHttpService_1.GatewayHttpService(config, input.callBroker);
81
83
  return {
82
84
  config,
@@ -17,6 +17,7 @@ const collabSemantics_1 = require("./collabSemantics");
17
17
  const collabUi_1 = require("./collabUi");
18
18
  const proxyFetch_1 = require("./proxyFetch");
19
19
  const client_1 = require("../tmux/client");
20
+ const versionHandshake_1 = require("../../lib/version/versionHandshake");
20
21
  const LOCAL_INDEX_FILE_NAME = "LOCAL_INDEX.md";
21
22
  function trimTrailingSlashes(value) {
22
23
  return value.replace(/\/+$/u, "");
@@ -25,6 +26,14 @@ function normalizeBasePath(value) {
25
26
  const trimmed = trimTrailingSlashes(value.trim());
26
27
  return trimmed.startsWith("/") ? trimmed || "/" : `/${trimmed || ""}`;
27
28
  }
29
+ function joinHttpPath(prefix, suffix) {
30
+ const normalizedPrefix = prefix ? normalizeBasePath(prefix) : "";
31
+ const normalizedSuffix = normalizeBasePath(suffix);
32
+ if (!normalizedPrefix || normalizedPrefix === "/") {
33
+ return normalizedSuffix;
34
+ }
35
+ return `${normalizedPrefix}${normalizedSuffix}`.replace(/\/{2,}/gu, "/");
36
+ }
28
37
  function resolveWebAppPublicBaseUrl(config) {
29
38
  if (!config.webapp.publicUrl) {
30
39
  return null;
@@ -755,6 +764,92 @@ class TelegramTransport {
755
764
  recoveredSessions: recoveredCount,
756
765
  });
757
766
  }
767
+ async sendStartupNotifications() {
768
+ const packageVersion = (0, versionHandshake_1.getTellyMcpPackageVersion)(__dirname);
769
+ const sessions = await this.sessionStore.listSessions();
770
+ const groupedRecipients = new Map();
771
+ for (const session of sessions) {
772
+ const binding = await this.bindingStore.getBinding(session.sessionId);
773
+ if (!binding) {
774
+ continue;
775
+ }
776
+ const key = `${binding.telegramChatId}:${binding.telegramUserId}`;
777
+ const current = groupedRecipients.get(key);
778
+ if (current) {
779
+ current.sessionIds.push(session.sessionId);
780
+ current.sessionLabels.push(session.label ?? session.sessionId);
781
+ continue;
782
+ }
783
+ groupedRecipients.set(key, {
784
+ binding: {
785
+ telegramChatId: binding.telegramChatId,
786
+ telegramUserId: binding.telegramUserId,
787
+ },
788
+ sessionIds: [session.sessionId],
789
+ sessionLabels: [session.label ?? session.sessionId],
790
+ });
791
+ }
792
+ if (groupedRecipients.size === 0) {
793
+ this.logger.info("Skipping startup notifications because no Telegram sessions are paired");
794
+ return;
795
+ }
796
+ const runtimePort = this.config.distributed.mode === "gateway" || this.config.distributed.mode === "both"
797
+ ? Number(process.env.PORT || this.config.mcp.httpPort)
798
+ : this.config.mcp.httpPort;
799
+ const rootPrefix = this.config.distributed.mode === "gateway" || this.config.distributed.mode === "both"
800
+ ? normalizeBasePath(process.env.ROOT_PREFIX || "/api")
801
+ : "";
802
+ const localMcpPath = this.config.distributed.mode === "gateway" || this.config.distributed.mode === "both"
803
+ ? joinHttpPath(rootPrefix, this.config.mcp.httpPath)
804
+ : this.config.mcp.httpPath;
805
+ const localWebappPath = this.config.distributed.mode === "gateway" || this.config.distributed.mode === "both"
806
+ ? joinHttpPath(rootPrefix, this.config.webapp.basePath)
807
+ : this.config.webapp.basePath;
808
+ const localMcpUrl = `http://${this.config.mcp.httpHost}:${runtimePort}${localMcpPath}`;
809
+ const localWebappUrl = `http://${this.config.mcp.httpHost}:${runtimePort}${localWebappPath}`;
810
+ for (const recipientGroup of groupedRecipients.values()) {
811
+ const primarySessionId = recipientGroup.sessionIds[0];
812
+ if (!primarySessionId) {
813
+ continue;
814
+ }
815
+ const uniqueSessionLabels = Array.from(new Set(recipientGroup.sessionLabels)).sort();
816
+ const startupMessage = [
817
+ "✅ TellyMCP запущен.",
818
+ `Версия: ${packageVersion}`,
819
+ `Протокол: ${versionHandshake_1.TELLYMCP_PROTOCOL_VERSION}`,
820
+ `Режим: ${this.config.distributed.mode}`,
821
+ ...(this.config.telegram.botUsername
822
+ ? [`Бот: @${this.config.telegram.botUsername.replace(/^@/u, "")}`]
823
+ : []),
824
+ `Сессии: ${uniqueSessionLabels.join(", ")}`,
825
+ `MCP: ${localMcpUrl}`,
826
+ ...(this.config.webapp.enabled ? [`WebApp: ${localWebappUrl}`] : []),
827
+ ...(this.config.distributed.gatewayPublicUrl
828
+ ? [`Gateway: ${this.config.distributed.gatewayPublicUrl}`]
829
+ : []),
830
+ ...(this.config.distributed.gatewayWsUrl
831
+ ? [`Gateway WS: ${this.config.distributed.gatewayWsUrl}`]
832
+ : []),
833
+ `Browser: ${this.config.browser.enabled ? (this.config.browser.headless ? "enabled, headless" : "enabled, headed") : "disabled"}`,
834
+ "Напиши /menu, чтобы открыть меню сессий.",
835
+ ].join("\n");
836
+ try {
837
+ await this.sendNotification({
838
+ sessionId: primarySessionId,
839
+ sessionLabel: "TellyMCP",
840
+ recipient: recipientGroup.binding,
841
+ message: startupMessage,
842
+ });
843
+ }
844
+ catch (error) {
845
+ this.logger.warn("Failed to deliver Telegram startup notification", {
846
+ telegramChatId: recipientGroup.binding.telegramChatId,
847
+ telegramUserId: recipientGroup.binding.telegramUserId,
848
+ error: error instanceof Error ? error.message : String(error),
849
+ });
850
+ }
851
+ }
852
+ }
758
853
  async sendRequest(input) {
759
854
  const text = (0, messageFormat_1.formatTelegramMessage)(input, {
760
855
  maxQuestionChars: this.config.telegram.maxQuestionChars,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deadragdoll/tellymcp",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "TellyMCP - Telegram Human-in-the-Loop MCP Server",
5
5
  "main": "dist/services/features/telegram-mcp/runtime.service.js",
6
6
  "bin": {
@@ -14,6 +14,7 @@
14
14
  "README-ru.md",
15
15
  "STANDALONE.md",
16
16
  "STANDALONE-ru.md",
17
+ "VERSION.md",
17
18
  "CHANGELOG.md",
18
19
  "TOOLS.md",
19
20
  ".env.example.client",